xpdf-3.03/0000755000076400007640000000000011622305345011713 5ustar derekndereknxpdf-3.03/misc/0000755000076400007640000000000011622305345012646 5ustar derekndereknxpdf-3.03/misc/xpdf.dt0000644000076400007640000000135711622305345014146 0ustar dereknderekn# simple CDE action for xpdf # written by Roland.Mainz@informatik.med.uni-giessen.de # # To use, copy this file into $HOME/.dt/types # # NOTE: this overrides the actions AcroRead and AcroReadPrint # defined in /usr/dt/appconfig/types/C/solaris.dt ACTION AcroRead { TYPE COMMAND WINDOW_TYPE NO_STDIO EXEC_STRING xpdf "%(File)Arg_1%" } # NOTE: Add a '-level1' switch to pdftops if your printer does not # support Level 2 Postscript. ACTION AcroReadPrint { TYPE COMMAND WINDOW_TYPE NO_STDIO EXEC_STRING ksh -c ' \ MYFILE="%(File)Arg_1%" ; \ pdftops "${MYFILE}" /dev/stdout | \ dtlp -w -b "${MYFILE}"' } # EOF. xpdf-3.03/misc/hello.pdf0000644000076400007640000000162511622305345014450 0ustar dereknderekn%PDF-1.2 %庆彚 7 0 obj <> stream x𶁽T0A(潨薝萓╜僎晒 N!\鶤 F !i\ 鍲 @慭. 徳湝|咈蛺,.匑瓳.r別ndstream endobj 8 0 obj 79 endobj 9 0 obj <> endobj 6 0 obj <> /Contents 7 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 6 0 R ] /Count 1 >> endobj 1 0 obj <> endobj 5 0 obj <> endobj 4 0 obj <> endobj 2 0 obj <>endobj xref 0 10 0000000000 65535 f 0000000402 00000 n 0000000584 00000 n 0000000343 00000 n 0000000523 00000 n 0000000450 00000 n 0000000211 00000 n 0000000015 00000 n 0000000164 00000 n 0000000182 00000 n trailer << /Size 10 /Root 1 0 R /Info 2 0 R >> startxref 640 %%EOF xpdf-3.03/xpdf/0000755000076400007640000000000011622305345012654 5ustar derekndereknxpdf-3.03/xpdf/CoreOutputDev.cc0000644000076400007640000000271211622305345015735 0ustar dereknderekn//======================================================================== // // CoreOutputDev.cc // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "Object.h" #include "TextOutputDev.h" #include "CoreOutputDev.h" //------------------------------------------------------------------------ // CoreOutputDev //------------------------------------------------------------------------ CoreOutputDev::CoreOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool incrementalUpdateA, CoreOutRedrawCbk redrawCbkA, void *redrawCbkDataA): SplashOutputDev(colorModeA, bitmapRowPadA, reverseVideoA, paperColorA) { incrementalUpdate = incrementalUpdateA; redrawCbk = redrawCbkA; redrawCbkData = redrawCbkDataA; } CoreOutputDev::~CoreOutputDev() { } void CoreOutputDev::endPage() { SplashOutputDev::endPage(); if (!incrementalUpdate) { (*redrawCbk)(redrawCbkData, 0, 0, getBitmapWidth(), getBitmapHeight(), gTrue); } } void CoreOutputDev::dump() { int x0, y0, x1, y1; if (incrementalUpdate) { getModRegion(&x0, &y0, &x1, &y1); clearModRegion(); if (x1 >= x0 && y1 >= y0) { (*redrawCbk)(redrawCbkData, x0, y0, x1, y1, gFalse); } } } void CoreOutputDev::clear() { startDoc(NULL); startPage(0, NULL); } xpdf-3.03/xpdf/Stream.cc0000644000076400007640000031604211622305345014424 0ustar dereknderekn//======================================================================== // // Stream.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #ifndef WIN32 #include #endif #include #include #include "gmem.h" #include "gfile.h" #include "config.h" #include "Error.h" #include "Object.h" #include "Lexer.h" #include "GfxState.h" #include "Stream.h" #include "JBIG2Stream.h" #include "JPXStream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ static GBool setDJSYSFLAGS = gFalse; #endif #ifdef VMS #ifdef __GNUC__ #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2 #endif #endif //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ Stream::Stream() { ref = 1; } Stream::~Stream() { } void Stream::close() { } int Stream::getRawChar() { error(errInternal, -1, "Called getRawChar() on non-predictor stream"); return EOF; } int Stream::getBlock(char *buf, int size) { int n, c; n = 0; while (n < size) { if ((c = getChar()) == EOF) { break; } buf[n++] = (char)c; } return n; } char *Stream::getLine(char *buf, int size) { int i; int c; if (lookChar() == EOF || size < 0) return NULL; for (i = 0; i < size - 1; ++i) { c = getChar(); if (c == EOF || c == '\n') break; if (c == '\r') { if ((c = lookChar()) == '\n') getChar(); break; } buf[i] = c; } buf[i] = '\0'; return buf; } GString *Stream::getPSFilter(int psLevel, const char *indent) { return new GString(); } Stream *Stream::addFilters(Object *dict) { Object obj, obj2; Object params, params2; Stream *str; int i; str = this; dict->dictLookup("Filter", &obj); if (obj.isNull()) { obj.free(); dict->dictLookup("F", &obj); } dict->dictLookup("DecodeParms", ¶ms); if (params.isNull()) { params.free(); dict->dictLookup("DP", ¶ms); } if (obj.isName()) { str = makeFilter(obj.getName(), str, ¶ms); } else if (obj.isArray()) { for (i = 0; i < obj.arrayGetLength(); ++i) { obj.arrayGet(i, &obj2); if (params.isArray()) params.arrayGet(i, ¶ms2); else params2.initNull(); if (obj2.isName()) { str = makeFilter(obj2.getName(), str, ¶ms2); } else { error(errSyntaxError, getPos(), "Bad filter name"); str = new EOFStream(str); } obj2.free(); params2.free(); } } else if (!obj.isNull()) { error(errSyntaxError, getPos(), "Bad 'Filter' attribute in stream"); } obj.free(); params.free(); return str; } Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int pred; // parameters int colors; int bits; int early; int encoding; GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; int colorXform; Object globals, obj; if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { str = new ASCIIHexStream(str); } else if (!strcmp(name, "ASCII85Decode") || !strcmp(name, "A85")) { str = new ASCII85Stream(str); } else if (!strcmp(name, "LZWDecode") || !strcmp(name, "LZW")) { pred = 1; columns = 1; colors = 1; bits = 8; early = 1; if (params->isDict()) { params->dictLookup("Predictor", &obj); if (obj.isInt()) pred = obj.getInt(); obj.free(); params->dictLookup("Columns", &obj); if (obj.isInt()) columns = obj.getInt(); obj.free(); params->dictLookup("Colors", &obj); if (obj.isInt()) colors = obj.getInt(); obj.free(); params->dictLookup("BitsPerComponent", &obj); if (obj.isInt()) bits = obj.getInt(); obj.free(); params->dictLookup("EarlyChange", &obj); if (obj.isInt()) early = obj.getInt(); obj.free(); } str = new LZWStream(str, pred, columns, colors, bits, early); } else if (!strcmp(name, "RunLengthDecode") || !strcmp(name, "RL")) { str = new RunLengthStream(str); } else if (!strcmp(name, "CCITTFaxDecode") || !strcmp(name, "CCF")) { encoding = 0; endOfLine = gFalse; byteAlign = gFalse; columns = 1728; rows = 0; endOfBlock = gTrue; black = gFalse; if (params->isDict()) { params->dictLookup("K", &obj); if (obj.isInt()) { encoding = obj.getInt(); } obj.free(); params->dictLookup("EndOfLine", &obj); if (obj.isBool()) { endOfLine = obj.getBool(); } obj.free(); params->dictLookup("EncodedByteAlign", &obj); if (obj.isBool()) { byteAlign = obj.getBool(); } obj.free(); params->dictLookup("Columns", &obj); if (obj.isInt()) { columns = obj.getInt(); } obj.free(); params->dictLookup("Rows", &obj); if (obj.isInt()) { rows = obj.getInt(); } obj.free(); params->dictLookup("EndOfBlock", &obj); if (obj.isBool()) { endOfBlock = obj.getBool(); } obj.free(); params->dictLookup("BlackIs1", &obj); if (obj.isBool()) { black = obj.getBool(); } obj.free(); } str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, columns, rows, endOfBlock, black); } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { colorXform = -1; if (params->isDict()) { if (params->dictLookup("ColorTransform", &obj)->isInt()) { colorXform = obj.getInt(); } obj.free(); } str = new DCTStream(str, colorXform); } else if (!strcmp(name, "FlateDecode") || !strcmp(name, "Fl")) { pred = 1; columns = 1; colors = 1; bits = 8; if (params->isDict()) { params->dictLookup("Predictor", &obj); if (obj.isInt()) pred = obj.getInt(); obj.free(); params->dictLookup("Columns", &obj); if (obj.isInt()) columns = obj.getInt(); obj.free(); params->dictLookup("Colors", &obj); if (obj.isInt()) colors = obj.getInt(); obj.free(); params->dictLookup("BitsPerComponent", &obj); if (obj.isInt()) bits = obj.getInt(); obj.free(); } str = new FlateStream(str, pred, columns, colors, bits); } else if (!strcmp(name, "JBIG2Decode")) { if (params->isDict()) { params->dictLookup("JBIG2Globals", &globals); } str = new JBIG2Stream(str, &globals); globals.free(); } else if (!strcmp(name, "JPXDecode")) { str = new JPXStream(str); } else { error(errSyntaxError, getPos(), "Unknown filter '{0:s}'", name); str = new EOFStream(str); } return str; } //------------------------------------------------------------------------ // BaseStream //------------------------------------------------------------------------ BaseStream::BaseStream(Object *dictA) { dict = *dictA; } BaseStream::~BaseStream() { dict.free(); } //------------------------------------------------------------------------ // FilterStream //------------------------------------------------------------------------ FilterStream::FilterStream(Stream *strA) { str = strA; } FilterStream::~FilterStream() { } void FilterStream::close() { str->close(); } void FilterStream::setPos(Guint pos, int dir) { error(errInternal, -1, "Called setPos() on FilterStream"); } //------------------------------------------------------------------------ // ImageStream //------------------------------------------------------------------------ ImageStream::ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA) { int imgLineSize; str = strA; width = widthA; nComps = nCompsA; nBits = nBitsA; nVals = width * nComps; inputLineSize = (nVals * nBits + 7) >> 3; if (nVals > INT_MAX / nBits - 7) { // force a call to gmallocn(-1,...), which will throw an exception inputLineSize = -1; } inputLine = (char *)gmallocn(inputLineSize, sizeof(char)); if (nBits == 8) { imgLine = (Guchar *)inputLine; } else { if (nBits == 1) { imgLineSize = (nVals + 7) & ~7; } else { imgLineSize = nVals; } if (width > INT_MAX / nComps) { // force a call to gmallocn(-1,...), which will throw an exception imgLineSize = -1; } imgLine = (Guchar *)gmallocn(imgLineSize, sizeof(Guchar)); } imgIdx = nVals; } ImageStream::~ImageStream() { if (imgLine != (Guchar *)inputLine) { gfree(imgLine); } gfree(inputLine); } void ImageStream::reset() { str->reset(); } GBool ImageStream::getPixel(Guchar *pix) { int i; if (imgIdx >= nVals) { if (!getLine()) { return gFalse; } imgIdx = 0; } for (i = 0; i < nComps; ++i) { pix[i] = imgLine[imgIdx++]; } return gTrue; } Guchar *ImageStream::getLine() { Gulong buf, bitMask; int bits; int c; int i; char *p; if (str->getBlock(inputLine, inputLineSize) != inputLineSize) { return NULL; } if (nBits == 1) { p = inputLine; for (i = 0; i < nVals; i += 8) { c = *p++; imgLine[i+0] = (Guchar)((c >> 7) & 1); imgLine[i+1] = (Guchar)((c >> 6) & 1); imgLine[i+2] = (Guchar)((c >> 5) & 1); imgLine[i+3] = (Guchar)((c >> 4) & 1); imgLine[i+4] = (Guchar)((c >> 3) & 1); imgLine[i+5] = (Guchar)((c >> 2) & 1); imgLine[i+6] = (Guchar)((c >> 1) & 1); imgLine[i+7] = (Guchar)(c & 1); } } else if (nBits == 8) { // special case: imgLine == inputLine } else { bitMask = (1 << nBits) - 1; buf = 0; bits = 0; p = inputLine; for (i = 0; i < nVals; ++i) { if (bits < nBits) { buf = (buf << 8) | (*p++ & 0xff); bits += 8; } imgLine[i] = (Guchar)((buf >> (bits - nBits)) & bitMask); bits -= nBits; } } return imgLine; } void ImageStream::skipLine() { str->getBlock(inputLine, inputLineSize); } //------------------------------------------------------------------------ // StreamPredictor //------------------------------------------------------------------------ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA) { str = strA; predictor = predictorA; width = widthA; nComps = nCompsA; nBits = nBitsA; predLine = NULL; ok = gFalse; nVals = width * nComps; pixBytes = (nComps * nBits + 7) >> 3; rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; if (width <= 0 || nComps <= 0 || nBits <= 0 || nComps > gfxColorMaxComps || nBits > 16 || width >= INT_MAX / nComps || // check for overflow in nVals nVals >= (INT_MAX - 7) / nBits) { // check for overflow in rowBytes return; } predLine = (Guchar *)gmalloc(rowBytes); memset(predLine, 0, rowBytes); predIdx = rowBytes; ok = gTrue; } StreamPredictor::~StreamPredictor() { gfree(predLine); } int StreamPredictor::lookChar() { if (predIdx >= rowBytes) { if (!getNextLine()) { return EOF; } } return predLine[predIdx]; } int StreamPredictor::getChar() { if (predIdx >= rowBytes) { if (!getNextLine()) { return EOF; } } return predLine[predIdx++]; } int StreamPredictor::getBlock(char *blk, int size) { int n, m; n = 0; while (n < size) { if (predIdx >= rowBytes) { if (!getNextLine()) { break; } } m = rowBytes - predIdx; if (m > size - n) { m = size - n; } memcpy(blk + n, predLine + predIdx, m); predIdx += m; n += m; } return n; } GBool StreamPredictor::getNextLine() { int curPred; Guchar upLeftBuf[gfxColorMaxComps * 2 + 1]; int left, up, upLeft, p, pa, pb, pc; int c; Gulong inBuf, outBuf, bitMask; int inBits, outBits; int i, j, k, kk; // get PNG optimum predictor number if (predictor >= 10) { if ((curPred = str->getRawChar()) == EOF) { return gFalse; } curPred += 10; } else { curPred = predictor; } // read the raw line, apply PNG (byte) predictor memset(upLeftBuf, 0, pixBytes + 1); for (i = pixBytes; i < rowBytes; ++i) { for (j = pixBytes; j > 0; --j) { upLeftBuf[j] = upLeftBuf[j-1]; } upLeftBuf[0] = predLine[i]; if ((c = str->getRawChar()) == EOF) { if (i > pixBytes) { // this ought to return false, but some (broken) PDF files // contain truncated image data, and Adobe apparently reads the // last partial line break; } return gFalse; } switch (curPred) { case 11: // PNG sub predLine[i] = predLine[i - pixBytes] + (Guchar)c; break; case 12: // PNG up predLine[i] = predLine[i] + (Guchar)c; break; case 13: // PNG average predLine[i] = ((predLine[i - pixBytes] + predLine[i]) >> 1) + (Guchar)c; break; case 14: // PNG Paeth left = predLine[i - pixBytes]; up = predLine[i]; upLeft = upLeftBuf[pixBytes]; p = left + up - upLeft; if ((pa = p - left) < 0) pa = -pa; if ((pb = p - up) < 0) pb = -pb; if ((pc = p - upLeft) < 0) pc = -pc; if (pa <= pb && pa <= pc) predLine[i] = left + (Guchar)c; else if (pb <= pc) predLine[i] = up + (Guchar)c; else predLine[i] = upLeft + (Guchar)c; break; case 10: // PNG none default: // no predictor or TIFF predictor predLine[i] = (Guchar)c; break; } } // apply TIFF (component) predictor if (predictor == 2) { if (nBits == 1) { inBuf = predLine[pixBytes - 1]; for (i = pixBytes; i < rowBytes; i += 8) { // 1-bit add is just xor inBuf = (inBuf << 8) | predLine[i]; predLine[i] ^= inBuf >> nComps; } } else if (nBits == 8) { for (i = pixBytes; i < rowBytes; ++i) { predLine[i] += predLine[i - nComps]; } } else { memset(upLeftBuf, 0, nComps + 1); bitMask = (1 << nBits) - 1; inBuf = outBuf = 0; inBits = outBits = 0; j = k = pixBytes; for (i = 0; i < width; ++i) { for (kk = 0; kk < nComps; ++kk) { if (inBits < nBits) { inBuf = (inBuf << 8) | (predLine[j++] & 0xff); inBits += 8; } upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] + (inBuf >> (inBits - nBits))) & bitMask); inBits -= nBits; outBuf = (outBuf << nBits) | upLeftBuf[kk]; outBits += nBits; if (outBits >= 8) { predLine[k++] = (Guchar)(outBuf >> (outBits - 8)); outBits -= 8; } } } if (outBits > 0) { predLine[k++] = (Guchar)((outBuf << (8 - outBits)) + (inBuf & ((1 << (8 - outBits)) - 1))); } } } // reset to start of line predIdx = pixBytes; return gTrue; } //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ FileStream::FileStream(FILE *fA, Guint startA, GBool limitedA, Guint lengthA, Object *dictA): BaseStream(dictA) { f = fA; start = startA; limited = limitedA; length = lengthA; bufPtr = bufEnd = buf; bufPos = start; savePos = 0; saved = gFalse; } FileStream::~FileStream() { close(); } Stream *FileStream::makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA) { return new FileStream(f, startA, limitedA, lengthA, dictA); } void FileStream::reset() { #if HAVE_FSEEKO savePos = (Guint)ftello(f); fseeko(f, start, SEEK_SET); #elif HAVE_FSEEK64 savePos = (Guint)ftell64(f); fseek64(f, start, SEEK_SET); #else savePos = (Guint)ftell(f); fseek(f, start, SEEK_SET); #endif saved = gTrue; bufPtr = bufEnd = buf; bufPos = start; } void FileStream::close() { if (saved) { #if HAVE_FSEEKO fseeko(f, savePos, SEEK_SET); #elif HAVE_FSEEK64 fseek64(f, savePos, SEEK_SET); #else fseek(f, savePos, SEEK_SET); #endif saved = gFalse; } } int FileStream::getBlock(char *blk, int size) { int n, m; n = 0; while (n < size) { if (bufPtr >= bufEnd) { if (!fillBuf()) { break; } } m = (int)(bufEnd - bufPtr); if (m > size - n) { m = size - n; } memcpy(blk + n, bufPtr, m); bufPtr += m; n += m; } return n; } GBool FileStream::fillBuf() { int n; bufPos += (int)(bufEnd - buf); bufPtr = bufEnd = buf; if (limited && bufPos >= start + length) { return gFalse; } if (limited && bufPos + fileStreamBufSize > start + length) { n = start + length - bufPos; } else { n = fileStreamBufSize; } n = (int)fread(buf, 1, n, f); bufEnd = buf + n; if (bufPtr >= bufEnd) { return gFalse; } return gTrue; } void FileStream::setPos(Guint pos, int dir) { Guint size; if (dir >= 0) { #if HAVE_FSEEKO fseeko(f, pos, SEEK_SET); #elif HAVE_FSEEK64 fseek64(f, pos, SEEK_SET); #else fseek(f, pos, SEEK_SET); #endif bufPos = pos; } else { #if HAVE_FSEEKO fseeko(f, 0, SEEK_END); size = (Guint)ftello(f); #elif HAVE_FSEEK64 fseek64(f, 0, SEEK_END); size = (Guint)ftell64(f); #else fseek(f, 0, SEEK_END); size = (Guint)ftell(f); #endif if (pos > size) pos = (Guint)size; #if HAVE_FSEEKO fseeko(f, -(int)pos, SEEK_END); bufPos = (Guint)ftello(f); #elif HAVE_FSEEK64 fseek64(f, -(int)pos, SEEK_END); bufPos = (Guint)ftell64(f); #else fseek(f, -(int)pos, SEEK_END); bufPos = (Guint)ftell(f); #endif } bufPtr = bufEnd = buf; } void FileStream::moveStart(int delta) { start += delta; bufPtr = bufEnd = buf; bufPos = start; } //------------------------------------------------------------------------ // MemStream //------------------------------------------------------------------------ MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA): BaseStream(dictA) { buf = bufA; start = startA; length = lengthA; bufEnd = buf + start + length; bufPtr = buf + start; needFree = gFalse; } MemStream::~MemStream() { if (needFree) { gfree(buf); } } Stream *MemStream::makeSubStream(Guint startA, GBool limited, Guint lengthA, Object *dictA) { MemStream *subStr; Guint newLength; if (!limited || startA + lengthA > start + length) { newLength = start + length - startA; } else { newLength = lengthA; } subStr = new MemStream(buf, startA, newLength, dictA); return subStr; } void MemStream::reset() { bufPtr = buf + start; } void MemStream::close() { } int MemStream::getBlock(char *blk, int size) { int n; if (size <= 0) { return 0; } if (bufEnd - bufPtr < size) { n = (int)(bufEnd - bufPtr); } else { n = size; } memcpy(blk, bufPtr, n); bufPtr += n; return n; } void MemStream::setPos(Guint pos, int dir) { Guint i; if (dir >= 0) { i = pos; } else { i = start + length - pos; } if (i < start) { i = start; } else if (i > start + length) { i = start + length; } bufPtr = buf + i; } void MemStream::moveStart(int delta) { start += delta; length -= delta; bufPtr = buf + start; } //------------------------------------------------------------------------ // EmbedStream //------------------------------------------------------------------------ EmbedStream::EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA): BaseStream(dictA) { str = strA; limited = limitedA; length = lengthA; } EmbedStream::~EmbedStream() { } Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, Guint lengthA, Object *dictA) { error(errInternal, -1, "Called makeSubStream() on EmbedStream"); return NULL; } int EmbedStream::getChar() { if (limited && !length) { return EOF; } --length; return str->getChar(); } int EmbedStream::lookChar() { if (limited && !length) { return EOF; } return str->lookChar(); } int EmbedStream::getBlock(char *blk, int size) { if (size <= 0) { return 0; } if (limited && length < (Guint)size) { size = (int)length; } return str->getBlock(blk, size); } void EmbedStream::setPos(Guint pos, int dir) { error(errInternal, -1, "Called setPos() on EmbedStream"); } Guint EmbedStream::getStart() { error(errInternal, -1, "Called getStart() on EmbedStream"); return 0; } void EmbedStream::moveStart(int delta) { error(errInternal, -1, "Called moveStart() on EmbedStream"); } //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ ASCIIHexStream::ASCIIHexStream(Stream *strA): FilterStream(strA) { buf = EOF; eof = gFalse; } ASCIIHexStream::~ASCIIHexStream() { delete str; } void ASCIIHexStream::reset() { str->reset(); buf = EOF; eof = gFalse; } int ASCIIHexStream::lookChar() { int c1, c2, x; if (buf != EOF) return buf; if (eof) { buf = EOF; return EOF; } do { c1 = str->getChar(); } while (isspace(c1)); if (c1 == '>') { eof = gTrue; buf = EOF; return buf; } do { c2 = str->getChar(); } while (isspace(c2)); if (c2 == '>') { eof = gTrue; c2 = '0'; } if (c1 >= '0' && c1 <= '9') { x = (c1 - '0') << 4; } else if (c1 >= 'A' && c1 <= 'F') { x = (c1 - 'A' + 10) << 4; } else if (c1 >= 'a' && c1 <= 'f') { x = (c1 - 'a' + 10) << 4; } else if (c1 == EOF) { eof = gTrue; x = 0; } else { error(errSyntaxError, getPos(), "Illegal character <{0:02x}> in ASCIIHex stream", c1); x = 0; } if (c2 >= '0' && c2 <= '9') { x += c2 - '0'; } else if (c2 >= 'A' && c2 <= 'F') { x += c2 - 'A' + 10; } else if (c2 >= 'a' && c2 <= 'f') { x += c2 - 'a' + 10; } else if (c2 == EOF) { eof = gTrue; x = 0; } else { error(errSyntaxError, getPos(), "Illegal character <{0:02x}> in ASCIIHex stream", c2); } buf = x & 0xff; return buf; } GString *ASCIIHexStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCIIHexDecode filter\n"); return s; } GBool ASCIIHexStream::isBinary(GBool last) { return str->isBinary(gFalse); } //------------------------------------------------------------------------ // ASCII85Stream //------------------------------------------------------------------------ ASCII85Stream::ASCII85Stream(Stream *strA): FilterStream(strA) { index = n = 0; eof = gFalse; } ASCII85Stream::~ASCII85Stream() { delete str; } void ASCII85Stream::reset() { str->reset(); index = n = 0; eof = gFalse; } int ASCII85Stream::lookChar() { int k; Gulong t; if (index >= n) { if (eof) return EOF; index = 0; do { c[0] = str->getChar(); } while (Lexer::isSpace(c[0])); if (c[0] == '~' || c[0] == EOF) { eof = gTrue; n = 0; return EOF; } else if (c[0] == 'z') { b[0] = b[1] = b[2] = b[3] = 0; n = 4; } else { for (k = 1; k < 5; ++k) { do { c[k] = str->getChar(); } while (Lexer::isSpace(c[k])); if (c[k] == '~' || c[k] == EOF) break; } n = k - 1; if (k < 5 && (c[k] == '~' || c[k] == EOF)) { for (++k; k < 5; ++k) c[k] = 0x21 + 84; eof = gTrue; } t = 0; for (k = 0; k < 5; ++k) t = t * 85 + (c[k] - 0x21); for (k = 3; k >= 0; --k) { b[k] = (int)(t & 0xff); t >>= 8; } } } return b[index]; } GString *ASCII85Stream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/ASCII85Decode filter\n"); return s; } GBool ASCII85Stream::isBinary(GBool last) { return str->isBinary(gFalse); } //------------------------------------------------------------------------ // LZWStream //------------------------------------------------------------------------ LZWStream::LZWStream(Stream *strA, int predictor, int columns, int colors, int bits, int earlyA): FilterStream(strA) { if (predictor != 1) { pred = new StreamPredictor(this, predictor, columns, colors, bits); if (!pred->isOk()) { delete pred; pred = NULL; } } else { pred = NULL; } early = earlyA; eof = gFalse; inputBits = 0; clearTable(); } LZWStream::~LZWStream() { if (pred) { delete pred; } delete str; } int LZWStream::getChar() { if (pred) { return pred->getChar(); } if (eof) { return EOF; } if (seqIndex >= seqLength) { if (!processNextCode()) { return EOF; } } return seqBuf[seqIndex++]; } int LZWStream::lookChar() { if (pred) { return pred->lookChar(); } if (eof) { return EOF; } if (seqIndex >= seqLength) { if (!processNextCode()) { return EOF; } } return seqBuf[seqIndex]; } int LZWStream::getRawChar() { if (eof) { return EOF; } if (seqIndex >= seqLength) { if (!processNextCode()) { return EOF; } } return seqBuf[seqIndex++]; } int LZWStream::getBlock(char *blk, int size) { int n, m; if (pred) { return pred->getBlock(blk, size); } if (eof) { return 0; } n = 0; while (n < size) { if (seqIndex >= seqLength) { if (!processNextCode()) { break; } } m = seqLength - seqIndex; if (m > size - n) { m = size - n; } memcpy(blk + n, seqBuf + seqIndex, m); seqIndex += m; n += m; } return n; } void LZWStream::reset() { str->reset(); eof = gFalse; inputBits = 0; clearTable(); } GBool LZWStream::processNextCode() { int code; int nextLength; int i, j; // check for EOF if (eof) { return gFalse; } // check for eod and clear-table codes start: code = getCode(); if (code == EOF || code == 257) { eof = gTrue; return gFalse; } if (code == 256) { clearTable(); goto start; } if (nextCode >= 4097) { error(errSyntaxError, getPos(), "Bad LZW stream - expected clear-table code"); clearTable(); } // process the next code nextLength = seqLength + 1; if (code < 256) { seqBuf[0] = code; seqLength = 1; } else if (code < nextCode) { seqLength = table[code].length; for (i = seqLength - 1, j = code; i > 0; --i) { seqBuf[i] = table[j].tail; j = table[j].head; } seqBuf[0] = j; } else if (code == nextCode) { seqBuf[seqLength] = newChar; ++seqLength; } else { error(errSyntaxError, getPos(), "Bad LZW stream - unexpected code"); eof = gTrue; return gFalse; } newChar = seqBuf[0]; if (first) { first = gFalse; } else { table[nextCode].length = nextLength; table[nextCode].head = prevCode; table[nextCode].tail = newChar; ++nextCode; if (nextCode + early == 512) nextBits = 10; else if (nextCode + early == 1024) nextBits = 11; else if (nextCode + early == 2048) nextBits = 12; } prevCode = code; // reset buffer seqIndex = 0; return gTrue; } void LZWStream::clearTable() { nextCode = 258; nextBits = 9; seqIndex = seqLength = 0; first = gTrue; } int LZWStream::getCode() { int c; int code; while (inputBits < nextBits) { if ((c = str->getChar()) == EOF) return EOF; inputBuf = (inputBuf << 8) | (c & 0xff); inputBits += 8; } code = (inputBuf >> (inputBits - nextBits)) & ((1 << nextBits) - 1); inputBits -= nextBits; return code; } GString *LZWStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2 || pred) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< "); if (!early) { s->append("/EarlyChange 0 "); } s->append(">> /LZWDecode filter\n"); return s; } GBool LZWStream::isBinary(GBool last) { return str->isBinary(gTrue); } //------------------------------------------------------------------------ // RunLengthStream //------------------------------------------------------------------------ RunLengthStream::RunLengthStream(Stream *strA): FilterStream(strA) { bufPtr = bufEnd = buf; eof = gFalse; } RunLengthStream::~RunLengthStream() { delete str; } void RunLengthStream::reset() { str->reset(); bufPtr = bufEnd = buf; eof = gFalse; } int RunLengthStream::getBlock(char *blk, int size) { int n, m; n = 0; while (n < size) { if (bufPtr >= bufEnd) { if (!fillBuf()) { break; } } m = (int)(bufEnd - bufPtr); if (m > size - n) { m = size - n; } memcpy(blk + n, bufPtr, m); bufPtr += m; n += m; } return n; } GString *RunLengthStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("/RunLengthDecode filter\n"); return s; } GBool RunLengthStream::isBinary(GBool last) { return str->isBinary(gTrue); } GBool RunLengthStream::fillBuf() { int c; int n, i; if (eof) return gFalse; c = str->getChar(); if (c == 0x80 || c == EOF) { eof = gTrue; return gFalse; } if (c < 0x80) { n = c + 1; for (i = 0; i < n; ++i) buf[i] = (char)str->getChar(); } else { n = 0x101 - c; c = str->getChar(); for (i = 0; i < n; ++i) buf[i] = (char)c; } bufPtr = buf; bufEnd = buf + n; return gTrue; } //------------------------------------------------------------------------ // CCITTFaxStream //------------------------------------------------------------------------ CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, GBool byteAlignA, int columnsA, int rowsA, GBool endOfBlockA, GBool blackA): FilterStream(strA) { encoding = encodingA; endOfLine = endOfLineA; byteAlign = byteAlignA; columns = columnsA; if (columns < 1) { columns = 1; } else if (columns > INT_MAX - 2) { columns = INT_MAX - 2; } rows = rowsA; endOfBlock = endOfBlockA; black = blackA; // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = columns // ---> max codingLine size = columns + 1 // refLine has one extra guard entry at the end // ---> max refLine size = columns + 2 codingLine = (int *)gmallocn(columns + 1, sizeof(int)); refLine = (int *)gmallocn(columns + 2, sizeof(int)); eof = gFalse; row = 0; nextLine2D = encoding < 0; inputBits = 0; codingLine[0] = columns; a0i = 0; outputBits = 0; buf = EOF; } CCITTFaxStream::~CCITTFaxStream() { delete str; gfree(refLine); gfree(codingLine); } void CCITTFaxStream::reset() { int code1; str->reset(); eof = gFalse; row = 0; nextLine2D = encoding < 0; inputBits = 0; codingLine[0] = columns; a0i = 0; outputBits = 0; buf = EOF; // skip any initial zero bits and end-of-line marker, and get the 2D // encoding tag while ((code1 = lookBits(12)) == 0) { eatBits(1); } if (code1 == 0x001) { eatBits(12); endOfLine = gTrue; } if (encoding > 0) { nextLine2D = !lookBits(1); eatBits(1); } } inline void CCITTFaxStream::addPixels(int a1, int blackPixels) { if (a1 > codingLine[a0i]) { if (a1 > columns) { error(errSyntaxError, getPos(), "CCITTFax row is wrong length ({0:d})", a1); err = gTrue; a1 = columns; } if ((a0i & 1) ^ blackPixels) { ++a0i; } codingLine[a0i] = a1; } } inline void CCITTFaxStream::addPixelsNeg(int a1, int blackPixels) { if (a1 > codingLine[a0i]) { if (a1 > columns) { error(errSyntaxError, getPos(), "CCITTFax row is wrong length ({0:d})", a1); err = gTrue; a1 = columns; } if ((a0i & 1) ^ blackPixels) { ++a0i; } codingLine[a0i] = a1; } else if (a1 < codingLine[a0i]) { if (a1 < 0) { error(errSyntaxError, getPos(), "Invalid CCITTFax code"); err = gTrue; a1 = 0; } while (a0i > 0 && a1 <= codingLine[a0i - 1]) { --a0i; } codingLine[a0i] = a1; } } int CCITTFaxStream::lookChar() { int code1, code2, code3; int b1i, blackPixels, i, bits; GBool gotEOL; if (buf != EOF) { return buf; } // read the next row if (outputBits == 0) { // if at eof just return EOF if (eof) { return EOF; } err = gFalse; // 2-D encoding if (nextLine2D) { for (i = 0; codingLine[i] < columns; ++i) { refLine[i] = codingLine[i]; } refLine[i++] = columns; refLine[i] = columns; codingLine[0] = 0; a0i = 0; b1i = 0; blackPixels = 0; // invariant: // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] // <= columns // exception at left edge: // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible // exception at right edge: // refLine[b1i] = refLine[b1i+1] = columns is possible while (codingLine[a0i] < columns) { code1 = getTwoDimCode(); switch (code1) { case twoDimPass: addPixels(refLine[b1i + 1], blackPixels); if (refLine[b1i + 1] < columns) { b1i += 2; } break; case twoDimHoriz: code1 = code2 = 0; if (blackPixels) { do { code1 += code3 = getBlackCode(); } while (code3 >= 64); do { code2 += code3 = getWhiteCode(); } while (code3 >= 64); } else { do { code1 += code3 = getWhiteCode(); } while (code3 >= 64); do { code2 += code3 = getBlackCode(); } while (code3 >= 64); } addPixels(codingLine[a0i] + code1, blackPixels); if (codingLine[a0i] < columns) { addPixels(codingLine[a0i] + code2, blackPixels ^ 1); } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } break; case twoDimVertR3: addPixels(refLine[b1i] + 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVertR2: addPixels(refLine[b1i] + 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVertR1: addPixels(refLine[b1i] + 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVert0: addPixels(refLine[b1i], blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVertL3: addPixelsNeg(refLine[b1i] - 3, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVertL2: addPixelsNeg(refLine[b1i] - 2, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case twoDimVertL1: addPixelsNeg(refLine[b1i] - 1, blackPixels); blackPixels ^= 1; if (codingLine[a0i] < columns) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < columns) { b1i += 2; } } break; case EOF: addPixels(columns, 0); eof = gTrue; break; default: error(errSyntaxError, getPos(), "Bad 2D code {0:04x} in CCITTFax stream", code1); addPixels(columns, 0); err = gTrue; break; } } // 1-D encoding } else { codingLine[0] = 0; a0i = 0; blackPixels = 0; while (codingLine[a0i] < columns) { code1 = 0; if (blackPixels) { do { code1 += code3 = getBlackCode(); } while (code3 >= 64); } else { do { code1 += code3 = getWhiteCode(); } while (code3 >= 64); } addPixels(codingLine[a0i] + code1, blackPixels); blackPixels ^= 1; } } // check for end-of-line marker, skipping over any extra zero bits // (if EncodedByteAlign is true and EndOfLine is false, there can // be "false" EOL markers -- i.e., if the last n unused bits in // row i are set to zero, and the first 11-n bits in row i+1 // happen to be zero -- so we don't look for EOL markers in this // case) gotEOL = gFalse; if (!endOfBlock && row == rows - 1) { eof = gTrue; } else if (endOfLine || !byteAlign) { code1 = lookBits(12); if (endOfLine) { while (code1 != EOF && code1 != 0x001) { eatBits(1); code1 = lookBits(12); } } else { while (code1 == 0) { eatBits(1); code1 = lookBits(12); } } if (code1 == 0x001) { eatBits(12); gotEOL = gTrue; } } // byte-align the row // (Adobe apparently doesn't do byte alignment after EOL markers // -- I've seen CCITT image data streams in two different formats, // both with the byteAlign flag set: // 1. xx:x0:01:yy:yy // 2. xx:00:1y:yy:yy // where xx is the previous line, yy is the next line, and colons // separate bytes.) if (byteAlign && !gotEOL) { inputBits &= ~7; } // check for end of stream if (lookBits(1) == EOF) { eof = gTrue; } // get 2D encoding tag if (!eof && encoding > 0) { nextLine2D = !lookBits(1); eatBits(1); } // check for end-of-block marker if (endOfBlock && !endOfLine && byteAlign) { // in this case, we didn't check for an EOL code above, so we // need to check here code1 = lookBits(24); if (code1 == 0x001001) { eatBits(12); gotEOL = gTrue; } } if (endOfBlock && gotEOL) { code1 = lookBits(12); if (code1 == 0x001) { eatBits(12); if (encoding > 0) { lookBits(1); eatBits(1); } if (encoding >= 0) { for (i = 0; i < 4; ++i) { code1 = lookBits(12); if (code1 != 0x001) { error(errSyntaxError, getPos(), "Bad RTC code in CCITTFax stream"); } eatBits(12); if (encoding > 0) { lookBits(1); eatBits(1); } } } eof = gTrue; } // look for an end-of-line marker after an error -- we only do // this if we know the stream contains end-of-line markers because // the "just plow on" technique tends to work better otherwise } else if (err && endOfLine) { while (1) { code1 = lookBits(13); if (code1 == EOF) { eof = gTrue; return EOF; } if ((code1 >> 1) == 0x001) { break; } eatBits(1); } eatBits(12); if (encoding > 0) { eatBits(1); nextLine2D = !(code1 & 1); } } // set up for output if (codingLine[0] > 0) { outputBits = codingLine[a0i = 0]; } else { outputBits = codingLine[a0i = 1]; } ++row; } // get a byte if (outputBits >= 8) { buf = (a0i & 1) ? 0x00 : 0xff; outputBits -= 8; if (outputBits == 0 && codingLine[a0i] < columns) { ++a0i; outputBits = codingLine[a0i] - codingLine[a0i - 1]; } } else { bits = 8; buf = 0; do { if (outputBits > bits) { buf <<= bits; if (!(a0i & 1)) { buf |= 0xff >> (8 - bits); } outputBits -= bits; bits = 0; } else { buf <<= outputBits; if (!(a0i & 1)) { buf |= 0xff >> (8 - outputBits); } bits -= outputBits; outputBits = 0; if (codingLine[a0i] < columns) { ++a0i; outputBits = codingLine[a0i] - codingLine[a0i - 1]; } else if (bits > 0) { buf <<= bits; bits = 0; } } } while (bits); } if (black) { buf ^= 0xff; } return buf; } short CCITTFaxStream::getTwoDimCode() { int code; CCITTCode *p; int n; code = 0; // make gcc happy if (endOfBlock) { if ((code = lookBits(7)) != EOF) { p = &twoDimTab1[code]; if (p->bits > 0) { eatBits(p->bits); return p->n; } } } else { for (n = 1; n <= 7; ++n) { if ((code = lookBits(n)) == EOF) { break; } if (n < 7) { code <<= 7 - n; } p = &twoDimTab1[code]; if (p->bits == n) { eatBits(n); return p->n; } } } error(errSyntaxError, getPos(), "Bad two dim code ({0:04x}) in CCITTFax stream", code); return EOF; } short CCITTFaxStream::getWhiteCode() { short code; CCITTCode *p; int n; code = 0; // make gcc happy if (endOfBlock) { code = lookBits(12); if (code == EOF) { return 1; } if ((code >> 5) == 0) { p = &whiteTab1[code]; } else { p = &whiteTab2[code >> 3]; } if (p->bits > 0) { eatBits(p->bits); return p->n; } } else { for (n = 1; n <= 9; ++n) { code = lookBits(n); if (code == EOF) { return 1; } if (n < 9) { code <<= 9 - n; } p = &whiteTab2[code]; if (p->bits == n) { eatBits(n); return p->n; } } for (n = 11; n <= 12; ++n) { code = lookBits(n); if (code == EOF) { return 1; } if (n < 12) { code <<= 12 - n; } p = &whiteTab1[code]; if (p->bits == n) { eatBits(n); return p->n; } } } error(errSyntaxError, getPos(), "Bad white code ({0:04x}) in CCITTFax stream", code); // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop eatBits(1); return 1; } short CCITTFaxStream::getBlackCode() { short code; CCITTCode *p; int n; code = 0; // make gcc happy if (endOfBlock) { code = lookBits(13); if (code == EOF) { return 1; } if ((code >> 7) == 0) { p = &blackTab1[code]; } else if ((code >> 9) == 0 && (code >> 7) != 0) { p = &blackTab2[(code >> 1) - 64]; } else { p = &blackTab3[code >> 7]; } if (p->bits > 0) { eatBits(p->bits); return p->n; } } else { for (n = 2; n <= 6; ++n) { code = lookBits(n); if (code == EOF) { return 1; } if (n < 6) { code <<= 6 - n; } p = &blackTab3[code]; if (p->bits == n) { eatBits(n); return p->n; } } for (n = 7; n <= 12; ++n) { code = lookBits(n); if (code == EOF) { return 1; } if (n < 12) { code <<= 12 - n; } if (code >= 64) { p = &blackTab2[code - 64]; if (p->bits == n) { eatBits(n); return p->n; } } } for (n = 10; n <= 13; ++n) { code = lookBits(n); if (code == EOF) { return 1; } if (n < 13) { code <<= 13 - n; } p = &blackTab1[code]; if (p->bits == n) { eatBits(n); return p->n; } } } error(errSyntaxError, getPos(), "Bad black code ({0:04x}) in CCITTFax stream", code); // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop eatBits(1); return 1; } short CCITTFaxStream::lookBits(int n) { int c; while (inputBits < n) { if ((c = str->getChar()) == EOF) { if (inputBits == 0) { return EOF; } // near the end of the stream, the caller may ask for more bits // than are available, but there may still be a valid code in // however many bits are available -- we need to return correct // data in this case return (inputBuf << (n - inputBits)) & (0xffffffff >> (32 - n)); } inputBuf = (inputBuf << 8) + c; inputBits += 8; } return (inputBuf >> (inputBits - n)) & (0xffffffff >> (32 - n)); } GString *CCITTFaxStream::getPSFilter(int psLevel, const char *indent) { GString *s; char s1[50]; if (psLevel < 2) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< "); if (encoding != 0) { sprintf(s1, "/K %d ", encoding); s->append(s1); } if (endOfLine) { s->append("/EndOfLine true "); } if (byteAlign) { s->append("/EncodedByteAlign true "); } sprintf(s1, "/Columns %d ", columns); s->append(s1); if (rows != 0) { sprintf(s1, "/Rows %d ", rows); s->append(s1); } if (!endOfBlock) { s->append("/EndOfBlock false "); } if (black) { s->append("/BlackIs1 true "); } s->append(">> /CCITTFaxDecode filter\n"); return s; } GBool CCITTFaxStream::isBinary(GBool last) { return str->isBinary(gTrue); } //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ // IDCT constants (20.12 fixed point format) #define dctCos1 4017 // cos(pi/16) #define dctSin1 799 // sin(pi/16) #define dctCos3 3406 // cos(3*pi/16) #define dctSin3 2276 // sin(3*pi/16) #define dctCos6 1567 // cos(6*pi/16) #define dctSin6 3784 // sin(6*pi/16) #define dctSqrt2 5793 // sqrt(2) #define dctSqrt1d2 2896 // sqrt(2) / 2 // color conversion parameters (16.16 fixed point format) #define dctCrToR 91881 // 1.4020 #define dctCbToG -22553 // -0.3441363 #define dctCrToG -46802 // -0.71413636 #define dctCbToB 116130 // 1.772 // clip [-256,511] --> [0,255] #define dctClipOffset 256 static Guchar dctClip[768]; static int dctClipInit = 0; // zig zag decode map static int dctZigZag[64] = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; DCTStream::DCTStream(Stream *strA, GBool colorXformA): FilterStream(strA) { int i, j; colorXform = colorXformA; progressive = interleaved = gFalse; width = height = 0; mcuWidth = mcuHeight = 0; numComps = 0; comp = 0; x = y = dy = 0; for (i = 0; i < 4; ++i) { for (j = 0; j < 32; ++j) { rowBuf[i][j] = NULL; } frameBuf[i] = NULL; } if (!dctClipInit) { for (i = -256; i < 0; ++i) dctClip[dctClipOffset + i] = 0; for (i = 0; i < 256; ++i) dctClip[dctClipOffset + i] = i; for (i = 256; i < 512; ++i) dctClip[dctClipOffset + i] = 255; dctClipInit = 1; } } DCTStream::~DCTStream() { close(); delete str; } void DCTStream::reset() { int i, j; str->reset(); progressive = interleaved = gFalse; width = height = 0; numComps = 0; numQuantTables = 0; numDCHuffTables = 0; numACHuffTables = 0; gotJFIFMarker = gFalse; gotAdobeMarker = gFalse; restartInterval = 0; if (!readHeader()) { y = height; return; } // compute MCU size if (numComps == 1) { compInfo[0].hSample = compInfo[0].vSample = 1; } mcuWidth = compInfo[0].hSample; mcuHeight = compInfo[0].vSample; for (i = 1; i < numComps; ++i) { if (compInfo[i].hSample > mcuWidth) { mcuWidth = compInfo[i].hSample; } if (compInfo[i].vSample > mcuHeight) { mcuHeight = compInfo[i].vSample; } } mcuWidth *= 8; mcuHeight *= 8; // figure out color transform if (colorXform == -1) { if (numComps == 3) { if (gotJFIFMarker) { colorXform = 1; } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && compInfo[2].id == 66) { // ASCII "RGB" colorXform = 0; } else { colorXform = 1; } } else { colorXform = 0; } } if (progressive || !interleaved) { // allocate a buffer for the whole image bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; bufHeight = ((height + mcuHeight - 1) / mcuHeight) * mcuHeight; if (bufWidth <= 0 || bufHeight <= 0 || bufWidth > INT_MAX / bufWidth / (int)sizeof(int)) { error(errSyntaxError, getPos(), "Invalid image size in DCT stream"); y = height; return; } for (i = 0; i < numComps; ++i) { frameBuf[i] = (int *)gmallocn(bufWidth * bufHeight, sizeof(int)); memset(frameBuf[i], 0, bufWidth * bufHeight * sizeof(int)); } // read the image data do { restartMarker = 0xd0; restart(); readScan(); } while (readHeader()); // decode decodeImage(); // initialize counters comp = 0; x = 0; y = 0; } else { // allocate a buffer for one row of MCUs bufWidth = ((width + mcuWidth - 1) / mcuWidth) * mcuWidth; for (i = 0; i < numComps; ++i) { for (j = 0; j < mcuHeight; ++j) { rowBuf[i][j] = (Guchar *)gmallocn(bufWidth, sizeof(Guchar)); } } // initialize counters comp = 0; x = 0; y = 0; dy = mcuHeight; restartMarker = 0xd0; restart(); } } void DCTStream::close() { int i, j; for (i = 0; i < 4; ++i) { for (j = 0; j < 32; ++j) { gfree(rowBuf[i][j]); rowBuf[i][j] = NULL; } gfree(frameBuf[i]); frameBuf[i] = NULL; } FilterStream::close(); } int DCTStream::getChar() { int c; if (y >= height) { return EOF; } if (progressive || !interleaved) { c = frameBuf[comp][y * bufWidth + x]; if (++comp == numComps) { comp = 0; if (++x == width) { x = 0; ++y; } } } else { if (dy >= mcuHeight) { if (!readMCURow()) { y = height; return EOF; } comp = 0; x = 0; dy = 0; } c = rowBuf[comp][dy][x]; if (++comp == numComps) { comp = 0; if (++x == width) { x = 0; ++y; ++dy; if (y == height) { readTrailer(); } } } } return c; } int DCTStream::lookChar() { if (y >= height) { return EOF; } if (progressive || !interleaved) { return frameBuf[comp][y * bufWidth + x]; } else { if (dy >= mcuHeight) { if (!readMCURow()) { y = height; return EOF; } comp = 0; x = 0; dy = 0; } return rowBuf[comp][dy][x]; } } void DCTStream::restart() { int i; inputBits = 0; restartCtr = restartInterval; for (i = 0; i < numComps; ++i) { compInfo[i].prevDC = 0; } eobRun = 0; } // Read one row of MCUs from a sequential JPEG stream. GBool DCTStream::readMCURow() { int data1[64]; Guchar data2[64]; Guchar *p1, *p2; int pY, pCb, pCr, pR, pG, pB; int h, v, horiz, vert, hSub, vSub; int x1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; int c; for (x1 = 0; x1 < width; x1 += mcuWidth) { // deal with restart marker if (restartInterval > 0 && restartCtr == 0) { c = readMarker(); if (c != restartMarker) { error(errSyntaxError, getPos(), "Bad DCT data: incorrect restart marker"); return gFalse; } if (++restartMarker == 0xd8) restartMarker = 0xd0; restart(); } // read one MCU for (cc = 0; cc < numComps; ++cc) { h = compInfo[cc].hSample; v = compInfo[cc].vSample; horiz = mcuWidth / h; vert = mcuHeight / v; hSub = horiz / 8; vSub = vert / 8; for (y2 = 0; y2 < mcuHeight; y2 += vert) { for (x2 = 0; x2 < mcuWidth; x2 += horiz) { if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, data1)) { return gFalse; } transformDataUnit(quantTables[compInfo[cc].quantTable], data1, data2); if (hSub == 1 && vSub == 1) { for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; p1[0] = data2[i]; p1[1] = data2[i+1]; p1[2] = data2[i+2]; p1[3] = data2[i+3]; p1[4] = data2[i+4]; p1[5] = data2[i+5]; p1[6] = data2[i+6]; p1[7] = data2[i+7]; } } else if (hSub == 2 && vSub == 2) { for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { p1 = &rowBuf[cc][y2+y3][x1+x2]; p2 = &rowBuf[cc][y2+y3+1][x1+x2]; p1[0] = p1[1] = p2[0] = p2[1] = data2[i]; p1[2] = p1[3] = p2[2] = p2[3] = data2[i+1]; p1[4] = p1[5] = p2[4] = p2[5] = data2[i+2]; p1[6] = p1[7] = p2[6] = p2[7] = data2[i+3]; p1[8] = p1[9] = p2[8] = p2[9] = data2[i+4]; p1[10] = p1[11] = p2[10] = p2[11] = data2[i+5]; p1[12] = p1[13] = p2[12] = p2[13] = data2[i+6]; p1[14] = p1[15] = p2[14] = p2[15] = data2[i+7]; } } else { i = 0; for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { for (y5 = 0; y5 < vSub; ++y5) for (x5 = 0; x5 < hSub; ++x5) rowBuf[cc][y2+y4+y5][x1+x2+x4+x5] = data2[i]; ++i; } } } } } } --restartCtr; // color space conversion if (colorXform) { // convert YCbCr to RGB if (numComps == 3) { for (y2 = 0; y2 < mcuHeight; ++y2) { for (x2 = 0; x2 < mcuWidth; ++x2) { pY = rowBuf[0][y2][x1+x2]; pCb = rowBuf[1][y2][x1+x2] - 128; pCr = rowBuf[2][y2][x1+x2] - 128; pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; rowBuf[0][y2][x1+x2] = dctClip[dctClipOffset + pR]; pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; rowBuf[1][y2][x1+x2] = dctClip[dctClipOffset + pG]; pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; rowBuf[2][y2][x1+x2] = dctClip[dctClipOffset + pB]; } } // convert YCbCrK to CMYK (K is passed through unchanged) } else if (numComps == 4) { for (y2 = 0; y2 < mcuHeight; ++y2) { for (x2 = 0; x2 < mcuWidth; ++x2) { pY = rowBuf[0][y2][x1+x2]; pCb = rowBuf[1][y2][x1+x2] - 128; pCr = rowBuf[2][y2][x1+x2] - 128; pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; rowBuf[0][y2][x1+x2] = 255 - dctClip[dctClipOffset + pR]; pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; rowBuf[1][y2][x1+x2] = 255 - dctClip[dctClipOffset + pG]; pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; rowBuf[2][y2][x1+x2] = 255 - dctClip[dctClipOffset + pB]; } } } } } return gTrue; } // Read one scan from a progressive or non-interleaved JPEG stream. void DCTStream::readScan() { int data[64]; int x1, y1, dx1, dy1, x2, y2, y3, cc, i; int h, v, horiz, vert, vSub; int *p1; int c; if (scanInfo.numComps == 1) { for (cc = 0; cc < numComps; ++cc) { if (scanInfo.comp[cc]) { break; } } dx1 = mcuWidth / compInfo[cc].hSample; dy1 = mcuHeight / compInfo[cc].vSample; } else { dx1 = mcuWidth; dy1 = mcuHeight; } for (y1 = 0; y1 < height; y1 += dy1) { for (x1 = 0; x1 < width; x1 += dx1) { // deal with restart marker if (restartInterval > 0 && restartCtr == 0) { c = readMarker(); if (c != restartMarker) { error(errSyntaxError, getPos(), "Bad DCT data: incorrect restart marker"); return; } if (++restartMarker == 0xd8) { restartMarker = 0xd0; } restart(); } // read one MCU for (cc = 0; cc < numComps; ++cc) { if (!scanInfo.comp[cc]) { continue; } h = compInfo[cc].hSample; v = compInfo[cc].vSample; horiz = mcuWidth / h; vert = mcuHeight / v; vSub = vert / 8; for (y2 = 0; y2 < dy1; y2 += vert) { for (x2 = 0; x2 < dx1; x2 += horiz) { // pull out the current values p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { data[i] = p1[0]; data[i+1] = p1[1]; data[i+2] = p1[2]; data[i+3] = p1[3]; data[i+4] = p1[4]; data[i+5] = p1[5]; data[i+6] = p1[6]; data[i+7] = p1[7]; p1 += bufWidth * vSub; } // read one data unit if (progressive) { if (!readProgressiveDataUnit( &dcHuffTables[scanInfo.dcHuffTable[cc]], &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, data)) { return; } } else { if (!readDataUnit(&dcHuffTables[scanInfo.dcHuffTable[cc]], &acHuffTables[scanInfo.acHuffTable[cc]], &compInfo[cc].prevDC, data)) { return; } } // add the data unit into frameBuf p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1[0] = data[i]; p1[1] = data[i+1]; p1[2] = data[i+2]; p1[3] = data[i+3]; p1[4] = data[i+4]; p1[5] = data[i+5]; p1[6] = data[i+6]; p1[7] = data[i+7]; p1 += bufWidth * vSub; } } } } --restartCtr; } } } // Read one data unit from a sequential JPEG stream. GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]) { int run, size, amp; int c; int i, j; if ((size = readHuffSym(dcHuffTable)) == 9999) { return gFalse; } if (size > 0) { if ((amp = readAmp(size)) == 9999) { return gFalse; } } else { amp = 0; } data[0] = *prevDC += amp; for (i = 1; i < 64; ++i) { data[i] = 0; } i = 1; while (i < 64) { run = 0; while ((c = readHuffSym(acHuffTable)) == 0xf0 && run < 0x30) { run += 0x10; } if (c == 9999) { return gFalse; } if (c == 0x00) { break; } else { run += (c >> 4) & 0x0f; size = c & 0x0f; amp = readAmp(size); if (amp == 9999) { return gFalse; } i += run; if (i < 64) { j = dctZigZag[i++]; data[j] = amp; } } } return gTrue; } // Read one data unit from a sequential JPEG stream. GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]) { int run, size, amp, bit, c; int i, j, k; // get the DC coefficient i = scanInfo.firstCoeff; if (i == 0) { if (scanInfo.ah == 0) { if ((size = readHuffSym(dcHuffTable)) == 9999) { return gFalse; } if (size > 0) { if ((amp = readAmp(size)) == 9999) { return gFalse; } } else { amp = 0; } data[0] += (*prevDC += amp) << scanInfo.al; } else { if ((bit = readBit()) == 9999) { return gFalse; } data[0] += bit << scanInfo.al; } ++i; } if (scanInfo.lastCoeff == 0) { return gTrue; } // check for an EOB run if (eobRun > 0) { while (i <= scanInfo.lastCoeff) { j = dctZigZag[i++]; if (data[j] != 0) { if ((bit = readBit()) == EOF) { return gFalse; } if (bit) { data[j] += 1 << scanInfo.al; } } } --eobRun; return gTrue; } // read the AC coefficients while (i <= scanInfo.lastCoeff) { if ((c = readHuffSym(acHuffTable)) == 9999) { return gFalse; } // ZRL if (c == 0xf0) { k = 0; while (k < 16 && i <= scanInfo.lastCoeff) { j = dctZigZag[i++]; if (data[j] == 0) { ++k; } else { if ((bit = readBit()) == EOF) { return gFalse; } if (bit) { data[j] += 1 << scanInfo.al; } } } // EOB run } else if ((c & 0x0f) == 0x00) { j = c >> 4; eobRun = 0; for (k = 0; k < j; ++k) { if ((bit = readBit()) == EOF) { return gFalse; } eobRun = (eobRun << 1) | bit; } eobRun += 1 << j; while (i <= scanInfo.lastCoeff) { j = dctZigZag[i++]; if (data[j] != 0) { if ((bit = readBit()) == EOF) { return gFalse; } if (bit) { data[j] += 1 << scanInfo.al; } } } --eobRun; break; // zero run and one AC coefficient } else { run = (c >> 4) & 0x0f; size = c & 0x0f; if ((amp = readAmp(size)) == 9999) { return gFalse; } j = 0; // make gcc happy for (k = 0; k <= run && i <= scanInfo.lastCoeff; ++k) { j = dctZigZag[i++]; while (data[j] != 0 && i <= scanInfo.lastCoeff) { if ((bit = readBit()) == EOF) { return gFalse; } if (bit) { data[j] += 1 << scanInfo.al; } j = dctZigZag[i++]; } } data[j] = amp << scanInfo.al; } } return gTrue; } // Decode a progressive JPEG image. void DCTStream::decodeImage() { int dataIn[64]; Guchar dataOut[64]; Gushort *quantTable; int pY, pCb, pCr, pR, pG, pB; int x1, y1, x2, y2, x3, y3, x4, y4, x5, y5, cc, i; int h, v, horiz, vert, hSub, vSub; int *p0, *p1, *p2; for (y1 = 0; y1 < bufHeight; y1 += mcuHeight) { for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) { for (cc = 0; cc < numComps; ++cc) { quantTable = quantTables[compInfo[cc].quantTable]; h = compInfo[cc].hSample; v = compInfo[cc].vSample; horiz = mcuWidth / h; vert = mcuHeight / v; hSub = horiz / 8; vSub = vert / 8; for (y2 = 0; y2 < mcuHeight; y2 += vert) { for (x2 = 0; x2 < mcuWidth; x2 += horiz) { // pull out the coded data unit p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { dataIn[i] = p1[0]; dataIn[i+1] = p1[1]; dataIn[i+2] = p1[2]; dataIn[i+3] = p1[3]; dataIn[i+4] = p1[4]; dataIn[i+5] = p1[5]; dataIn[i+6] = p1[6]; dataIn[i+7] = p1[7]; p1 += bufWidth * vSub; } // transform transformDataUnit(quantTable, dataIn, dataOut); // store back into frameBuf, doing replication for // subsampled components p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)]; if (hSub == 1 && vSub == 1) { for (y3 = 0, i = 0; y3 < 8; ++y3, i += 8) { p1[0] = dataOut[i] & 0xff; p1[1] = dataOut[i+1] & 0xff; p1[2] = dataOut[i+2] & 0xff; p1[3] = dataOut[i+3] & 0xff; p1[4] = dataOut[i+4] & 0xff; p1[5] = dataOut[i+5] & 0xff; p1[6] = dataOut[i+6] & 0xff; p1[7] = dataOut[i+7] & 0xff; p1 += bufWidth; } } else if (hSub == 2 && vSub == 2) { p2 = p1 + bufWidth; for (y3 = 0, i = 0; y3 < 16; y3 += 2, i += 8) { p1[0] = p1[1] = p2[0] = p2[1] = dataOut[i] & 0xff; p1[2] = p1[3] = p2[2] = p2[3] = dataOut[i+1] & 0xff; p1[4] = p1[5] = p2[4] = p2[5] = dataOut[i+2] & 0xff; p1[6] = p1[7] = p2[6] = p2[7] = dataOut[i+3] & 0xff; p1[8] = p1[9] = p2[8] = p2[9] = dataOut[i+4] & 0xff; p1[10] = p1[11] = p2[10] = p2[11] = dataOut[i+5] & 0xff; p1[12] = p1[13] = p2[12] = p2[13] = dataOut[i+6] & 0xff; p1[14] = p1[15] = p2[14] = p2[15] = dataOut[i+7] & 0xff; p1 += bufWidth * 2; p2 += bufWidth * 2; } } else { i = 0; for (y3 = 0, y4 = 0; y3 < 8; ++y3, y4 += vSub) { for (x3 = 0, x4 = 0; x3 < 8; ++x3, x4 += hSub) { p2 = p1 + x4; for (y5 = 0; y5 < vSub; ++y5) { for (x5 = 0; x5 < hSub; ++x5) { p2[x5] = dataOut[i] & 0xff; } p2 += bufWidth; } ++i; } p1 += bufWidth * vSub; } } } } } // color space conversion if (colorXform) { // convert YCbCr to RGB if (numComps == 3) { for (y2 = 0; y2 < mcuHeight; ++y2) { p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; for (x2 = 0; x2 < mcuWidth; ++x2) { pY = *p0; pCb = *p1 - 128; pCr = *p2 - 128; pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; *p0++ = dctClip[dctClipOffset + pR]; pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; *p1++ = dctClip[dctClipOffset + pG]; pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; *p2++ = dctClip[dctClipOffset + pB]; } } // convert YCbCrK to CMYK (K is passed through unchanged) } else if (numComps == 4) { for (y2 = 0; y2 < mcuHeight; ++y2) { p0 = &frameBuf[0][(y1+y2) * bufWidth + x1]; p1 = &frameBuf[1][(y1+y2) * bufWidth + x1]; p2 = &frameBuf[2][(y1+y2) * bufWidth + x1]; for (x2 = 0; x2 < mcuWidth; ++x2) { pY = *p0; pCb = *p1 - 128; pCr = *p2 - 128; pR = ((pY << 16) + dctCrToR * pCr + 32768) >> 16; *p0++ = 255 - dctClip[dctClipOffset + pR]; pG = ((pY << 16) + dctCbToG * pCb + dctCrToG * pCr + 32768) >> 16; *p1++ = 255 - dctClip[dctClipOffset + pG]; pB = ((pY << 16) + dctCbToB * pCb + 32768) >> 16; *p2++ = 255 - dctClip[dctClipOffset + pB]; } } } } } } } // Transform one data unit -- this performs the dequantization and // IDCT steps. This IDCT algorithm is taken from: // Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, // "Practical Fast 1-D DCT Algorithms with 11 Multiplications", // IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, // 988-991. // The stage numbers mentioned in the comments refer to Figure 1 in this // paper. void DCTStream::transformDataUnit(Gushort *quantTable, int dataIn[64], Guchar dataOut[64]) { int v0, v1, v2, v3, v4, v5, v6, v7, t; int *p; int i; // dequant for (i = 0; i < 64; ++i) { dataIn[i] *= quantTable[i]; } // inverse DCT on rows for (i = 0; i < 64; i += 8) { p = dataIn + i; // check for all-zero AC coefficients if (p[1] == 0 && p[2] == 0 && p[3] == 0 && p[4] == 0 && p[5] == 0 && p[6] == 0 && p[7] == 0) { t = (dctSqrt2 * p[0] + 512) >> 10; p[0] = t; p[1] = t; p[2] = t; p[3] = t; p[4] = t; p[5] = t; p[6] = t; p[7] = t; continue; } // stage 4 v0 = (dctSqrt2 * p[0] + 128) >> 8; v1 = (dctSqrt2 * p[4] + 128) >> 8; v2 = p[2]; v3 = p[6]; v4 = (dctSqrt1d2 * (p[1] - p[7]) + 128) >> 8; v7 = (dctSqrt1d2 * (p[1] + p[7]) + 128) >> 8; v5 = p[3] << 4; v6 = p[5] << 4; // stage 3 t = (v0 - v1+ 1) >> 1; v0 = (v0 + v1 + 1) >> 1; v1 = t; t = (v2 * dctSin6 + v3 * dctCos6 + 128) >> 8; v2 = (v2 * dctCos6 - v3 * dctSin6 + 128) >> 8; v3 = t; t = (v4 - v6 + 1) >> 1; v4 = (v4 + v6 + 1) >> 1; v6 = t; t = (v7 + v5 + 1) >> 1; v5 = (v7 - v5 + 1) >> 1; v7 = t; // stage 2 t = (v0 - v3 + 1) >> 1; v0 = (v0 + v3 + 1) >> 1; v3 = t; t = (v1 - v2 + 1) >> 1; v1 = (v1 + v2 + 1) >> 1; v2 = t; t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; v7 = t; t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; v6 = t; // stage 1 p[0] = v0 + v7; p[7] = v0 - v7; p[1] = v1 + v6; p[6] = v1 - v6; p[2] = v2 + v5; p[5] = v2 - v5; p[3] = v3 + v4; p[4] = v3 - v4; } // inverse DCT on columns for (i = 0; i < 8; ++i) { p = dataIn + i; // check for all-zero AC coefficients if (p[1*8] == 0 && p[2*8] == 0 && p[3*8] == 0 && p[4*8] == 0 && p[5*8] == 0 && p[6*8] == 0 && p[7*8] == 0) { t = (dctSqrt2 * dataIn[i+0] + 8192) >> 14; p[0*8] = t; p[1*8] = t; p[2*8] = t; p[3*8] = t; p[4*8] = t; p[5*8] = t; p[6*8] = t; p[7*8] = t; continue; } // stage 4 v0 = (dctSqrt2 * p[0*8] + 2048) >> 12; v1 = (dctSqrt2 * p[4*8] + 2048) >> 12; v2 = p[2*8]; v3 = p[6*8]; v4 = (dctSqrt1d2 * (p[1*8] - p[7*8]) + 2048) >> 12; v7 = (dctSqrt1d2 * (p[1*8] + p[7*8]) + 2048) >> 12; v5 = p[3*8]; v6 = p[5*8]; // stage 3 t = (v0 - v1 + 1) >> 1; v0 = (v0 + v1 + 1) >> 1; v1 = t; t = (v2 * dctSin6 + v3 * dctCos6 + 2048) >> 12; v2 = (v2 * dctCos6 - v3 * dctSin6 + 2048) >> 12; v3 = t; t = (v4 - v6 + 1) >> 1; v4 = (v4 + v6 + 1) >> 1; v6 = t; t = (v7 + v5 + 1) >> 1; v5 = (v7 - v5 + 1) >> 1; v7 = t; // stage 2 t = (v0 - v3 + 1) >> 1; v0 = (v0 + v3 + 1) >> 1; v3 = t; t = (v1 - v2 + 1) >> 1; v1 = (v1 + v2 + 1) >> 1; v2 = t; t = (v4 * dctSin3 + v7 * dctCos3 + 2048) >> 12; v4 = (v4 * dctCos3 - v7 * dctSin3 + 2048) >> 12; v7 = t; t = (v5 * dctSin1 + v6 * dctCos1 + 2048) >> 12; v5 = (v5 * dctCos1 - v6 * dctSin1 + 2048) >> 12; v6 = t; // stage 1 p[0*8] = v0 + v7; p[7*8] = v0 - v7; p[1*8] = v1 + v6; p[6*8] = v1 - v6; p[2*8] = v2 + v5; p[5*8] = v2 - v5; p[3*8] = v3 + v4; p[4*8] = v3 - v4; } // convert to 8-bit integers for (i = 0; i < 64; ++i) { dataOut[i] = dctClip[dctClipOffset + 128 + ((dataIn[i] + 8) >> 4)]; } } int DCTStream::readHuffSym(DCTHuffTable *table) { Gushort code; int bit; int codeBits; code = 0; codeBits = 0; do { // add a bit to the code if ((bit = readBit()) == EOF) { return 9999; } code = (code << 1) + bit; ++codeBits; // look up code if (code < table->firstCode[codeBits]) { break; } if (code - table->firstCode[codeBits] < table->numCodes[codeBits]) { code -= table->firstCode[codeBits]; return table->sym[table->firstSym[codeBits] + code]; } } while (codeBits < 16); error(errSyntaxError, getPos(), "Bad Huffman code in DCT stream"); return 9999; } int DCTStream::readAmp(int size) { int amp, bit; int bits; amp = 0; for (bits = 0; bits < size; ++bits) { if ((bit = readBit()) == EOF) return 9999; amp = (amp << 1) + bit; } if (amp < (1 << (size - 1))) amp -= (1 << size) - 1; return amp; } int DCTStream::readBit() { int bit; int c, c2; if (inputBits == 0) { if ((c = str->getChar()) == EOF) return EOF; if (c == 0xff) { do { c2 = str->getChar(); } while (c2 == 0xff); if (c2 != 0x00) { error(errSyntaxError, getPos(), "Bad DCT data: missing 00 after ff"); return EOF; } } inputBuf = c; inputBits = 8; } bit = (inputBuf >> (inputBits - 1)) & 1; --inputBits; return bit; } GBool DCTStream::readHeader() { GBool doScan; int n; int c = 0; int i; // read headers doScan = gFalse; while (!doScan) { c = readMarker(); switch (c) { case 0xc0: // SOF0 (sequential) case 0xc1: // SOF1 (extended sequential) if (!readBaselineSOF()) { return gFalse; } break; case 0xc2: // SOF2 (progressive) if (!readProgressiveSOF()) { return gFalse; } break; case 0xc4: // DHT if (!readHuffmanTables()) { return gFalse; } break; case 0xd8: // SOI break; case 0xd9: // EOI return gFalse; case 0xda: // SOS if (!readScanInfo()) { return gFalse; } doScan = gTrue; break; case 0xdb: // DQT if (!readQuantTables()) { return gFalse; } break; case 0xdd: // DRI if (!readRestartInterval()) { return gFalse; } break; case 0xe0: // APP0 if (!readJFIFMarker()) { return gFalse; } break; case 0xee: // APP14 if (!readAdobeMarker()) { return gFalse; } break; case EOF: error(errSyntaxError, getPos(), "Bad DCT header"); return gFalse; default: // skip APPn / COM / etc. if (c >= 0xe0) { n = read16() - 2; for (i = 0; i < n; ++i) { str->getChar(); } } else { error(errSyntaxError, getPos(), "Unknown DCT marker <{0:02x}>", c); return gFalse; } break; } } return gTrue; } GBool DCTStream::readBaselineSOF() { int length; int prec; int i; int c; length = read16(); prec = str->getChar(); height = read16(); width = read16(); numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { error(errSyntaxError, getPos(), "Bad number of components in DCT stream"); numComps = 0; return gFalse; } if (prec != 8) { error(errSyntaxError, getPos(), "Bad DCT precision {0:d}", prec); return gFalse; } for (i = 0; i < numComps; ++i) { compInfo[i].id = str->getChar(); c = str->getChar(); compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 || compInfo[i].vSample < 1 || compInfo[i].vSample > 4) { error(errSyntaxError, getPos(), "Bad DCT sampling factor"); return gFalse; } if (compInfo[i].quantTable < 0 || compInfo[i].quantTable > 3) { error(errSyntaxError, getPos(), "Bad DCT quant table selector"); return gFalse; } } progressive = gFalse; return gTrue; } GBool DCTStream::readProgressiveSOF() { int length; int prec; int i; int c; length = read16(); prec = str->getChar(); height = read16(); width = read16(); numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { error(errSyntaxError, getPos(), "Bad number of components in DCT stream"); numComps = 0; return gFalse; } if (prec != 8) { error(errSyntaxError, getPos(), "Bad DCT precision {0:d}", prec); return gFalse; } for (i = 0; i < numComps; ++i) { compInfo[i].id = str->getChar(); c = str->getChar(); compInfo[i].hSample = (c >> 4) & 0x0f; compInfo[i].vSample = c & 0x0f; compInfo[i].quantTable = str->getChar(); if (compInfo[i].hSample < 1 || compInfo[i].hSample > 4 || compInfo[i].vSample < 1 || compInfo[i].vSample > 4) { error(errSyntaxError, getPos(), "Bad DCT sampling factor"); return gFalse; } if (compInfo[i].quantTable < 0 || compInfo[i].quantTable > 3) { error(errSyntaxError, getPos(), "Bad DCT quant table selector"); return gFalse; } } progressive = gTrue; return gTrue; } GBool DCTStream::readScanInfo() { int length; int id, c; int i, j; length = read16() - 2; scanInfo.numComps = str->getChar(); if (scanInfo.numComps <= 0 || scanInfo.numComps > 4) { error(errSyntaxError, getPos(), "Bad number of components in DCT stream"); scanInfo.numComps = 0; return gFalse; } --length; if (length != 2 * scanInfo.numComps + 3) { error(errSyntaxError, getPos(), "Bad DCT scan info block"); return gFalse; } interleaved = scanInfo.numComps == numComps; for (j = 0; j < numComps; ++j) { scanInfo.comp[j] = gFalse; } for (i = 0; i < scanInfo.numComps; ++i) { id = str->getChar(); // some (broken) DCT streams reuse ID numbers, but at least they // keep the components in order, so we check compInfo[i] first to // work around the problem if (id == compInfo[i].id) { j = i; } else { for (j = 0; j < numComps; ++j) { if (id == compInfo[j].id) { break; } } if (j == numComps) { error(errSyntaxError, getPos(), "Bad DCT component ID in scan info block"); return gFalse; } } scanInfo.comp[j] = gTrue; c = str->getChar(); scanInfo.dcHuffTable[j] = (c >> 4) & 0x0f; scanInfo.acHuffTable[j] = c & 0x0f; } scanInfo.firstCoeff = str->getChar(); scanInfo.lastCoeff = str->getChar(); if (scanInfo.firstCoeff < 0 || scanInfo.lastCoeff > 63 || scanInfo.firstCoeff > scanInfo.lastCoeff) { error(errSyntaxError, getPos(), "Bad DCT coefficient numbers in scan info block"); return gFalse; } c = str->getChar(); scanInfo.ah = (c >> 4) & 0x0f; scanInfo.al = c & 0x0f; return gTrue; } GBool DCTStream::readQuantTables() { int length, prec, i, index; length = read16() - 2; while (length > 0) { index = str->getChar(); prec = (index >> 4) & 0x0f; index &= 0x0f; if (prec > 1 || index >= 4) { error(errSyntaxError, getPos(), "Bad DCT quantization table"); return gFalse; } if (index == numQuantTables) { numQuantTables = index + 1; } for (i = 0; i < 64; ++i) { if (prec) { quantTables[index][dctZigZag[i]] = read16(); } else { quantTables[index][dctZigZag[i]] = str->getChar(); } } if (prec) { length -= 129; } else { length -= 65; } } return gTrue; } GBool DCTStream::readHuffmanTables() { DCTHuffTable *tbl; int length; int index; Gushort code; Guchar sym; int i; int c; length = read16() - 2; while (length > 0) { index = str->getChar(); --length; if ((index & 0x0f) >= 4) { error(errSyntaxError, getPos(), "Bad DCT Huffman table"); return gFalse; } if (index & 0x10) { index &= 0x0f; if (index >= numACHuffTables) numACHuffTables = index+1; tbl = &acHuffTables[index]; } else { index &= 0x0f; if (index >= numDCHuffTables) numDCHuffTables = index+1; tbl = &dcHuffTables[index]; } sym = 0; code = 0; for (i = 1; i <= 16; ++i) { c = str->getChar(); tbl->firstSym[i] = sym; tbl->firstCode[i] = code; tbl->numCodes[i] = c; sym += c; code = (code + c) << 1; } length -= 16; for (i = 0; i < sym; ++i) tbl->sym[i] = str->getChar(); length -= sym; } return gTrue; } GBool DCTStream::readRestartInterval() { int length; length = read16(); if (length != 4) { error(errSyntaxError, getPos(), "Bad DCT restart interval"); return gFalse; } restartInterval = read16(); return gTrue; } GBool DCTStream::readJFIFMarker() { int length, i; char buf[5]; int c; length = read16(); length -= 2; if (length >= 5) { for (i = 0; i < 5; ++i) { if ((c = str->getChar()) == EOF) { error(errSyntaxError, getPos(), "Bad DCT APP0 marker"); return gFalse; } buf[i] = c; } length -= 5; if (!memcmp(buf, "JFIF\0", 5)) { gotJFIFMarker = gTrue; } } while (length > 0) { if (str->getChar() == EOF) { error(errSyntaxError, getPos(), "Bad DCT APP0 marker"); return gFalse; } --length; } return gTrue; } GBool DCTStream::readAdobeMarker() { int length, i; char buf[12]; int c; length = read16(); if (length < 14) { goto err; } for (i = 0; i < 12; ++i) { if ((c = str->getChar()) == EOF) { goto err; } buf[i] = c; } if (strncmp(buf, "Adobe", 5)) { goto err; } colorXform = buf[11]; gotAdobeMarker = gTrue; for (i = 14; i < length; ++i) { if (str->getChar() == EOF) { goto err; } } return gTrue; err: error(errSyntaxError, getPos(), "Bad DCT Adobe APP14 marker"); return gFalse; } GBool DCTStream::readTrailer() { int c; c = readMarker(); if (c != 0xd9) { // EOI error(errSyntaxError, getPos(), "Bad DCT trailer"); return gFalse; } return gTrue; } int DCTStream::readMarker() { int c; do { do { c = str->getChar(); } while (c != 0xff && c != EOF); do { c = str->getChar(); } while (c == 0xff); } while (c == 0x00); return c; } int DCTStream::read16() { int c1, c2; if ((c1 = str->getChar()) == EOF) return EOF; if ((c2 = str->getChar()) == EOF) return EOF; return (c1 << 8) + c2; } GString *DCTStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 2) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< >> /DCTDecode filter\n"); return s; } GBool DCTStream::isBinary(GBool last) { return str->isBinary(gTrue); } //------------------------------------------------------------------------ // FlateStream //------------------------------------------------------------------------ int FlateStream::codeLenCodeMap[flateMaxCodeLenCodes] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; FlateDecode FlateStream::lengthDecode[flateMaxLitCodes-257] = { {0, 3}, {0, 4}, {0, 5}, {0, 6}, {0, 7}, {0, 8}, {0, 9}, {0, 10}, {1, 11}, {1, 13}, {1, 15}, {1, 17}, {2, 19}, {2, 23}, {2, 27}, {2, 31}, {3, 35}, {3, 43}, {3, 51}, {3, 59}, {4, 67}, {4, 83}, {4, 99}, {4, 115}, {5, 131}, {5, 163}, {5, 195}, {5, 227}, {0, 258}, {0, 258}, {0, 258} }; FlateDecode FlateStream::distDecode[flateMaxDistCodes] = { { 0, 1}, { 0, 2}, { 0, 3}, { 0, 4}, { 1, 5}, { 1, 7}, { 2, 9}, { 2, 13}, { 3, 17}, { 3, 25}, { 4, 33}, { 4, 49}, { 5, 65}, { 5, 97}, { 6, 129}, { 6, 193}, { 7, 257}, { 7, 385}, { 8, 513}, { 8, 769}, { 9, 1025}, { 9, 1537}, {10, 2049}, {10, 3073}, {11, 4097}, {11, 6145}, {12, 8193}, {12, 12289}, {13, 16385}, {13, 24577} }; static FlateCode flateFixedLitCodeTabCodes[512] = { {7, 0x0100}, {8, 0x0050}, {8, 0x0010}, {8, 0x0118}, {7, 0x0110}, {8, 0x0070}, {8, 0x0030}, {9, 0x00c0}, {7, 0x0108}, {8, 0x0060}, {8, 0x0020}, {9, 0x00a0}, {8, 0x0000}, {8, 0x0080}, {8, 0x0040}, {9, 0x00e0}, {7, 0x0104}, {8, 0x0058}, {8, 0x0018}, {9, 0x0090}, {7, 0x0114}, {8, 0x0078}, {8, 0x0038}, {9, 0x00d0}, {7, 0x010c}, {8, 0x0068}, {8, 0x0028}, {9, 0x00b0}, {8, 0x0008}, {8, 0x0088}, {8, 0x0048}, {9, 0x00f0}, {7, 0x0102}, {8, 0x0054}, {8, 0x0014}, {8, 0x011c}, {7, 0x0112}, {8, 0x0074}, {8, 0x0034}, {9, 0x00c8}, {7, 0x010a}, {8, 0x0064}, {8, 0x0024}, {9, 0x00a8}, {8, 0x0004}, {8, 0x0084}, {8, 0x0044}, {9, 0x00e8}, {7, 0x0106}, {8, 0x005c}, {8, 0x001c}, {9, 0x0098}, {7, 0x0116}, {8, 0x007c}, {8, 0x003c}, {9, 0x00d8}, {7, 0x010e}, {8, 0x006c}, {8, 0x002c}, {9, 0x00b8}, {8, 0x000c}, {8, 0x008c}, {8, 0x004c}, {9, 0x00f8}, {7, 0x0101}, {8, 0x0052}, {8, 0x0012}, {8, 0x011a}, {7, 0x0111}, {8, 0x0072}, {8, 0x0032}, {9, 0x00c4}, {7, 0x0109}, {8, 0x0062}, {8, 0x0022}, {9, 0x00a4}, {8, 0x0002}, {8, 0x0082}, {8, 0x0042}, {9, 0x00e4}, {7, 0x0105}, {8, 0x005a}, {8, 0x001a}, {9, 0x0094}, {7, 0x0115}, {8, 0x007a}, {8, 0x003a}, {9, 0x00d4}, {7, 0x010d}, {8, 0x006a}, {8, 0x002a}, {9, 0x00b4}, {8, 0x000a}, {8, 0x008a}, {8, 0x004a}, {9, 0x00f4}, {7, 0x0103}, {8, 0x0056}, {8, 0x0016}, {8, 0x011e}, {7, 0x0113}, {8, 0x0076}, {8, 0x0036}, {9, 0x00cc}, {7, 0x010b}, {8, 0x0066}, {8, 0x0026}, {9, 0x00ac}, {8, 0x0006}, {8, 0x0086}, {8, 0x0046}, {9, 0x00ec}, {7, 0x0107}, {8, 0x005e}, {8, 0x001e}, {9, 0x009c}, {7, 0x0117}, {8, 0x007e}, {8, 0x003e}, {9, 0x00dc}, {7, 0x010f}, {8, 0x006e}, {8, 0x002e}, {9, 0x00bc}, {8, 0x000e}, {8, 0x008e}, {8, 0x004e}, {9, 0x00fc}, {7, 0x0100}, {8, 0x0051}, {8, 0x0011}, {8, 0x0119}, {7, 0x0110}, {8, 0x0071}, {8, 0x0031}, {9, 0x00c2}, {7, 0x0108}, {8, 0x0061}, {8, 0x0021}, {9, 0x00a2}, {8, 0x0001}, {8, 0x0081}, {8, 0x0041}, {9, 0x00e2}, {7, 0x0104}, {8, 0x0059}, {8, 0x0019}, {9, 0x0092}, {7, 0x0114}, {8, 0x0079}, {8, 0x0039}, {9, 0x00d2}, {7, 0x010c}, {8, 0x0069}, {8, 0x0029}, {9, 0x00b2}, {8, 0x0009}, {8, 0x0089}, {8, 0x0049}, {9, 0x00f2}, {7, 0x0102}, {8, 0x0055}, {8, 0x0015}, {8, 0x011d}, {7, 0x0112}, {8, 0x0075}, {8, 0x0035}, {9, 0x00ca}, {7, 0x010a}, {8, 0x0065}, {8, 0x0025}, {9, 0x00aa}, {8, 0x0005}, {8, 0x0085}, {8, 0x0045}, {9, 0x00ea}, {7, 0x0106}, {8, 0x005d}, {8, 0x001d}, {9, 0x009a}, {7, 0x0116}, {8, 0x007d}, {8, 0x003d}, {9, 0x00da}, {7, 0x010e}, {8, 0x006d}, {8, 0x002d}, {9, 0x00ba}, {8, 0x000d}, {8, 0x008d}, {8, 0x004d}, {9, 0x00fa}, {7, 0x0101}, {8, 0x0053}, {8, 0x0013}, {8, 0x011b}, {7, 0x0111}, {8, 0x0073}, {8, 0x0033}, {9, 0x00c6}, {7, 0x0109}, {8, 0x0063}, {8, 0x0023}, {9, 0x00a6}, {8, 0x0003}, {8, 0x0083}, {8, 0x0043}, {9, 0x00e6}, {7, 0x0105}, {8, 0x005b}, {8, 0x001b}, {9, 0x0096}, {7, 0x0115}, {8, 0x007b}, {8, 0x003b}, {9, 0x00d6}, {7, 0x010d}, {8, 0x006b}, {8, 0x002b}, {9, 0x00b6}, {8, 0x000b}, {8, 0x008b}, {8, 0x004b}, {9, 0x00f6}, {7, 0x0103}, {8, 0x0057}, {8, 0x0017}, {8, 0x011f}, {7, 0x0113}, {8, 0x0077}, {8, 0x0037}, {9, 0x00ce}, {7, 0x010b}, {8, 0x0067}, {8, 0x0027}, {9, 0x00ae}, {8, 0x0007}, {8, 0x0087}, {8, 0x0047}, {9, 0x00ee}, {7, 0x0107}, {8, 0x005f}, {8, 0x001f}, {9, 0x009e}, {7, 0x0117}, {8, 0x007f}, {8, 0x003f}, {9, 0x00de}, {7, 0x010f}, {8, 0x006f}, {8, 0x002f}, {9, 0x00be}, {8, 0x000f}, {8, 0x008f}, {8, 0x004f}, {9, 0x00fe}, {7, 0x0100}, {8, 0x0050}, {8, 0x0010}, {8, 0x0118}, {7, 0x0110}, {8, 0x0070}, {8, 0x0030}, {9, 0x00c1}, {7, 0x0108}, {8, 0x0060}, {8, 0x0020}, {9, 0x00a1}, {8, 0x0000}, {8, 0x0080}, {8, 0x0040}, {9, 0x00e1}, {7, 0x0104}, {8, 0x0058}, {8, 0x0018}, {9, 0x0091}, {7, 0x0114}, {8, 0x0078}, {8, 0x0038}, {9, 0x00d1}, {7, 0x010c}, {8, 0x0068}, {8, 0x0028}, {9, 0x00b1}, {8, 0x0008}, {8, 0x0088}, {8, 0x0048}, {9, 0x00f1}, {7, 0x0102}, {8, 0x0054}, {8, 0x0014}, {8, 0x011c}, {7, 0x0112}, {8, 0x0074}, {8, 0x0034}, {9, 0x00c9}, {7, 0x010a}, {8, 0x0064}, {8, 0x0024}, {9, 0x00a9}, {8, 0x0004}, {8, 0x0084}, {8, 0x0044}, {9, 0x00e9}, {7, 0x0106}, {8, 0x005c}, {8, 0x001c}, {9, 0x0099}, {7, 0x0116}, {8, 0x007c}, {8, 0x003c}, {9, 0x00d9}, {7, 0x010e}, {8, 0x006c}, {8, 0x002c}, {9, 0x00b9}, {8, 0x000c}, {8, 0x008c}, {8, 0x004c}, {9, 0x00f9}, {7, 0x0101}, {8, 0x0052}, {8, 0x0012}, {8, 0x011a}, {7, 0x0111}, {8, 0x0072}, {8, 0x0032}, {9, 0x00c5}, {7, 0x0109}, {8, 0x0062}, {8, 0x0022}, {9, 0x00a5}, {8, 0x0002}, {8, 0x0082}, {8, 0x0042}, {9, 0x00e5}, {7, 0x0105}, {8, 0x005a}, {8, 0x001a}, {9, 0x0095}, {7, 0x0115}, {8, 0x007a}, {8, 0x003a}, {9, 0x00d5}, {7, 0x010d}, {8, 0x006a}, {8, 0x002a}, {9, 0x00b5}, {8, 0x000a}, {8, 0x008a}, {8, 0x004a}, {9, 0x00f5}, {7, 0x0103}, {8, 0x0056}, {8, 0x0016}, {8, 0x011e}, {7, 0x0113}, {8, 0x0076}, {8, 0x0036}, {9, 0x00cd}, {7, 0x010b}, {8, 0x0066}, {8, 0x0026}, {9, 0x00ad}, {8, 0x0006}, {8, 0x0086}, {8, 0x0046}, {9, 0x00ed}, {7, 0x0107}, {8, 0x005e}, {8, 0x001e}, {9, 0x009d}, {7, 0x0117}, {8, 0x007e}, {8, 0x003e}, {9, 0x00dd}, {7, 0x010f}, {8, 0x006e}, {8, 0x002e}, {9, 0x00bd}, {8, 0x000e}, {8, 0x008e}, {8, 0x004e}, {9, 0x00fd}, {7, 0x0100}, {8, 0x0051}, {8, 0x0011}, {8, 0x0119}, {7, 0x0110}, {8, 0x0071}, {8, 0x0031}, {9, 0x00c3}, {7, 0x0108}, {8, 0x0061}, {8, 0x0021}, {9, 0x00a3}, {8, 0x0001}, {8, 0x0081}, {8, 0x0041}, {9, 0x00e3}, {7, 0x0104}, {8, 0x0059}, {8, 0x0019}, {9, 0x0093}, {7, 0x0114}, {8, 0x0079}, {8, 0x0039}, {9, 0x00d3}, {7, 0x010c}, {8, 0x0069}, {8, 0x0029}, {9, 0x00b3}, {8, 0x0009}, {8, 0x0089}, {8, 0x0049}, {9, 0x00f3}, {7, 0x0102}, {8, 0x0055}, {8, 0x0015}, {8, 0x011d}, {7, 0x0112}, {8, 0x0075}, {8, 0x0035}, {9, 0x00cb}, {7, 0x010a}, {8, 0x0065}, {8, 0x0025}, {9, 0x00ab}, {8, 0x0005}, {8, 0x0085}, {8, 0x0045}, {9, 0x00eb}, {7, 0x0106}, {8, 0x005d}, {8, 0x001d}, {9, 0x009b}, {7, 0x0116}, {8, 0x007d}, {8, 0x003d}, {9, 0x00db}, {7, 0x010e}, {8, 0x006d}, {8, 0x002d}, {9, 0x00bb}, {8, 0x000d}, {8, 0x008d}, {8, 0x004d}, {9, 0x00fb}, {7, 0x0101}, {8, 0x0053}, {8, 0x0013}, {8, 0x011b}, {7, 0x0111}, {8, 0x0073}, {8, 0x0033}, {9, 0x00c7}, {7, 0x0109}, {8, 0x0063}, {8, 0x0023}, {9, 0x00a7}, {8, 0x0003}, {8, 0x0083}, {8, 0x0043}, {9, 0x00e7}, {7, 0x0105}, {8, 0x005b}, {8, 0x001b}, {9, 0x0097}, {7, 0x0115}, {8, 0x007b}, {8, 0x003b}, {9, 0x00d7}, {7, 0x010d}, {8, 0x006b}, {8, 0x002b}, {9, 0x00b7}, {8, 0x000b}, {8, 0x008b}, {8, 0x004b}, {9, 0x00f7}, {7, 0x0103}, {8, 0x0057}, {8, 0x0017}, {8, 0x011f}, {7, 0x0113}, {8, 0x0077}, {8, 0x0037}, {9, 0x00cf}, {7, 0x010b}, {8, 0x0067}, {8, 0x0027}, {9, 0x00af}, {8, 0x0007}, {8, 0x0087}, {8, 0x0047}, {9, 0x00ef}, {7, 0x0107}, {8, 0x005f}, {8, 0x001f}, {9, 0x009f}, {7, 0x0117}, {8, 0x007f}, {8, 0x003f}, {9, 0x00df}, {7, 0x010f}, {8, 0x006f}, {8, 0x002f}, {9, 0x00bf}, {8, 0x000f}, {8, 0x008f}, {8, 0x004f}, {9, 0x00ff} }; FlateHuffmanTab FlateStream::fixedLitCodeTab = { flateFixedLitCodeTabCodes, 9 }; static FlateCode flateFixedDistCodeTabCodes[32] = { {5, 0x0000}, {5, 0x0010}, {5, 0x0008}, {5, 0x0018}, {5, 0x0004}, {5, 0x0014}, {5, 0x000c}, {5, 0x001c}, {5, 0x0002}, {5, 0x0012}, {5, 0x000a}, {5, 0x001a}, {5, 0x0006}, {5, 0x0016}, {5, 0x000e}, {0, 0x0000}, {5, 0x0001}, {5, 0x0011}, {5, 0x0009}, {5, 0x0019}, {5, 0x0005}, {5, 0x0015}, {5, 0x000d}, {5, 0x001d}, {5, 0x0003}, {5, 0x0013}, {5, 0x000b}, {5, 0x001b}, {5, 0x0007}, {5, 0x0017}, {5, 0x000f}, {0, 0x0000} }; FlateHuffmanTab FlateStream::fixedDistCodeTab = { flateFixedDistCodeTabCodes, 5 }; FlateStream::FlateStream(Stream *strA, int predictor, int columns, int colors, int bits): FilterStream(strA) { if (predictor != 1) { pred = new StreamPredictor(this, predictor, columns, colors, bits); if (!pred->isOk()) { delete pred; pred = NULL; } } else { pred = NULL; } litCodeTab.codes = NULL; distCodeTab.codes = NULL; memset(buf, 0, flateWindow); } FlateStream::~FlateStream() { if (litCodeTab.codes != fixedLitCodeTab.codes) { gfree(litCodeTab.codes); } if (distCodeTab.codes != fixedDistCodeTab.codes) { gfree(distCodeTab.codes); } if (pred) { delete pred; } delete str; } void FlateStream::reset() { int cmf, flg; index = 0; remain = 0; codeBuf = 0; codeSize = 0; compressedBlock = gFalse; endOfBlock = gTrue; eof = gTrue; str->reset(); // read header //~ need to look at window size? endOfBlock = eof = gTrue; cmf = str->getChar(); flg = str->getChar(); if (cmf == EOF || flg == EOF) return; if ((cmf & 0x0f) != 0x08) { error(errSyntaxError, getPos(), "Unknown compression method in flate stream"); return; } if ((((cmf << 8) + flg) % 31) != 0) { error(errSyntaxError, getPos(), "Bad FCHECK in flate stream"); return; } if (flg & 0x20) { error(errSyntaxError, getPos(), "FDICT bit set in flate stream"); return; } eof = gFalse; } int FlateStream::getChar() { int c; if (pred) { return pred->getChar(); } while (remain == 0) { if (endOfBlock && eof) return EOF; readSome(); } c = buf[index]; index = (index + 1) & flateMask; --remain; return c; } int FlateStream::lookChar() { int c; if (pred) { return pred->lookChar(); } while (remain == 0) { if (endOfBlock && eof) return EOF; readSome(); } c = buf[index]; return c; } int FlateStream::getRawChar() { int c; while (remain == 0) { if (endOfBlock && eof) return EOF; readSome(); } c = buf[index]; index = (index + 1) & flateMask; --remain; return c; } int FlateStream::getBlock(char *blk, int size) { int n; if (pred) { return pred->getBlock(blk, size); } n = 0; while (n < size) { if (endOfBlock && eof) { break; } if (remain == 0) { readSome(); } while (remain && n < size) { blk[n++] = buf[index]; index = (index + 1) & flateMask; --remain; } } return n; } GString *FlateStream::getPSFilter(int psLevel, const char *indent) { GString *s; if (psLevel < 3 || pred) { return NULL; } if (!(s = str->getPSFilter(psLevel, indent))) { return NULL; } s->append(indent)->append("<< >> /FlateDecode filter\n"); return s; } GBool FlateStream::isBinary(GBool last) { return str->isBinary(gTrue); } void FlateStream::readSome() { int code1, code2; int len, dist; int i, j, k; int c; if (endOfBlock) { if (!startBlock()) return; } if (compressedBlock) { if ((code1 = getHuffmanCodeWord(&litCodeTab)) == EOF) goto err; if (code1 < 256) { buf[index] = code1; remain = 1; } else if (code1 == 256) { endOfBlock = gTrue; remain = 0; } else { code1 -= 257; code2 = lengthDecode[code1].bits; if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) goto err; len = lengthDecode[code1].first + code2; if ((code1 = getHuffmanCodeWord(&distCodeTab)) == EOF) goto err; code2 = distDecode[code1].bits; if (code2 > 0 && (code2 = getCodeWord(code2)) == EOF) goto err; dist = distDecode[code1].first + code2; i = index; j = (index - dist) & flateMask; for (k = 0; k < len; ++k) { buf[i] = buf[j]; i = (i + 1) & flateMask; j = (j + 1) & flateMask; } remain = len; } } else { len = (blockLen < flateWindow) ? blockLen : flateWindow; for (i = 0, j = index; i < len; ++i, j = (j + 1) & flateMask) { if ((c = str->getChar()) == EOF) { endOfBlock = eof = gTrue; break; } buf[j] = c & 0xff; } remain = i; blockLen -= len; if (blockLen == 0) endOfBlock = gTrue; } return; err: error(errSyntaxError, getPos(), "Unexpected end of file in flate stream"); endOfBlock = eof = gTrue; remain = 0; } GBool FlateStream::startBlock() { int blockHdr; int c; int check; // free the code tables from the previous block if (litCodeTab.codes != fixedLitCodeTab.codes) { gfree(litCodeTab.codes); } litCodeTab.codes = NULL; if (distCodeTab.codes != fixedDistCodeTab.codes) { gfree(distCodeTab.codes); } distCodeTab.codes = NULL; // read block header blockHdr = getCodeWord(3); if (blockHdr & 1) eof = gTrue; blockHdr >>= 1; // uncompressed block if (blockHdr == 0) { compressedBlock = gFalse; if ((c = str->getChar()) == EOF) goto err; blockLen = c & 0xff; if ((c = str->getChar()) == EOF) goto err; blockLen |= (c & 0xff) << 8; if ((c = str->getChar()) == EOF) goto err; check = c & 0xff; if ((c = str->getChar()) == EOF) goto err; check |= (c & 0xff) << 8; if (check != (~blockLen & 0xffff)) error(errSyntaxError, getPos(), "Bad uncompressed block length in flate stream"); codeBuf = 0; codeSize = 0; // compressed block with fixed codes } else if (blockHdr == 1) { compressedBlock = gTrue; loadFixedCodes(); // compressed block with dynamic codes } else if (blockHdr == 2) { compressedBlock = gTrue; if (!readDynamicCodes()) { goto err; } // unknown block type } else { goto err; } endOfBlock = gFalse; return gTrue; err: error(errSyntaxError, getPos(), "Bad block header in flate stream"); endOfBlock = eof = gTrue; return gFalse; } void FlateStream::loadFixedCodes() { litCodeTab.codes = fixedLitCodeTab.codes; litCodeTab.maxLen = fixedLitCodeTab.maxLen; distCodeTab.codes = fixedDistCodeTab.codes; distCodeTab.maxLen = fixedDistCodeTab.maxLen; } GBool FlateStream::readDynamicCodes() { int numCodeLenCodes; int numLitCodes; int numDistCodes; int codeLenCodeLengths[flateMaxCodeLenCodes]; FlateHuffmanTab codeLenCodeTab; int len, repeat, code; int i; codeLenCodeTab.codes = NULL; // read lengths if ((numLitCodes = getCodeWord(5)) == EOF) { goto err; } numLitCodes += 257; if ((numDistCodes = getCodeWord(5)) == EOF) { goto err; } numDistCodes += 1; if ((numCodeLenCodes = getCodeWord(4)) == EOF) { goto err; } numCodeLenCodes += 4; if (numLitCodes > flateMaxLitCodes || numDistCodes > flateMaxDistCodes || numCodeLenCodes > flateMaxCodeLenCodes) { goto err; } // build the code length code table for (i = 0; i < flateMaxCodeLenCodes; ++i) { codeLenCodeLengths[i] = 0; } for (i = 0; i < numCodeLenCodes; ++i) { if ((codeLenCodeLengths[codeLenCodeMap[i]] = getCodeWord(3)) == -1) { goto err; } } compHuffmanCodes(codeLenCodeLengths, flateMaxCodeLenCodes, &codeLenCodeTab); // build the literal and distance code tables len = 0; repeat = 0; i = 0; while (i < numLitCodes + numDistCodes) { if ((code = getHuffmanCodeWord(&codeLenCodeTab)) == EOF) { goto err; } if (code == 16) { if ((repeat = getCodeWord(2)) == EOF) { goto err; } repeat += 3; if (i + repeat > numLitCodes + numDistCodes) { goto err; } for (; repeat > 0; --repeat) { codeLengths[i++] = len; } } else if (code == 17) { if ((repeat = getCodeWord(3)) == EOF) { goto err; } repeat += 3; if (i + repeat > numLitCodes + numDistCodes) { goto err; } len = 0; for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else if (code == 18) { if ((repeat = getCodeWord(7)) == EOF) { goto err; } repeat += 11; if (i + repeat > numLitCodes + numDistCodes) { goto err; } len = 0; for (; repeat > 0; --repeat) { codeLengths[i++] = 0; } } else { codeLengths[i++] = len = code; } } compHuffmanCodes(codeLengths, numLitCodes, &litCodeTab); compHuffmanCodes(codeLengths + numLitCodes, numDistCodes, &distCodeTab); gfree(codeLenCodeTab.codes); return gTrue; err: error(errSyntaxError, getPos(), "Bad dynamic code table in flate stream"); gfree(codeLenCodeTab.codes); return gFalse; } // Convert an array of lengths, in value order, into a // Huffman code lookup table. void FlateStream::compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab) { int tabSize, len, code, code2, skip, val, i, t; // find max code length tab->maxLen = 0; for (val = 0; val < n; ++val) { if (lengths[val] > tab->maxLen) { tab->maxLen = lengths[val]; } } // allocate the table tabSize = 1 << tab->maxLen; tab->codes = (FlateCode *)gmallocn(tabSize, sizeof(FlateCode)); // clear the table for (i = 0; i < tabSize; ++i) { tab->codes[i].len = 0; tab->codes[i].val = 0; } // build the table for (len = 1, code = 0, skip = 2; len <= tab->maxLen; ++len, code <<= 1, skip <<= 1) { for (val = 0; val < n; ++val) { if (lengths[val] == len) { // bit-reverse the code code2 = 0; t = code; for (i = 0; i < len; ++i) { code2 = (code2 << 1) | (t & 1); t >>= 1; } // fill in the table entries for (i = code2; i < tabSize; i += skip) { tab->codes[i].len = (Gushort)len; tab->codes[i].val = (Gushort)val; } ++code; } } } } int FlateStream::getHuffmanCodeWord(FlateHuffmanTab *tab) { FlateCode *code; int c; while (codeSize < tab->maxLen) { if ((c = str->getChar()) == EOF) { break; } codeBuf |= (c & 0xff) << codeSize; codeSize += 8; } code = &tab->codes[codeBuf & ((1 << tab->maxLen) - 1)]; if (codeSize == 0 || codeSize < code->len || code->len == 0) { return EOF; } codeBuf >>= code->len; codeSize -= code->len; return (int)code->val; } int FlateStream::getCodeWord(int bits) { int c; while (codeSize < bits) { if ((c = str->getChar()) == EOF) return EOF; codeBuf |= (c & 0xff) << codeSize; codeSize += 8; } c = codeBuf & ((1 << bits) - 1); codeBuf >>= bits; codeSize -= bits; return c; } //------------------------------------------------------------------------ // EOFStream //------------------------------------------------------------------------ EOFStream::EOFStream(Stream *strA): FilterStream(strA) { } EOFStream::~EOFStream() { delete str; } //------------------------------------------------------------------------ // BufStream //------------------------------------------------------------------------ BufStream::BufStream(Stream *strA, int bufSizeA): FilterStream(strA) { bufSize = bufSizeA; buf = (int *)gmallocn(bufSize, sizeof(int)); } BufStream::~BufStream() { gfree(buf); delete str; } void BufStream::reset() { int i; str->reset(); for (i = 0; i < bufSize; ++i) { buf[i] = str->getChar(); } } int BufStream::getChar() { int c, i; c = buf[0]; for (i = 1; i < bufSize; ++i) { buf[i-1] = buf[i]; } buf[bufSize - 1] = str->getChar(); return c; } int BufStream::lookChar() { return buf[0]; } int BufStream::lookChar(int idx) { return buf[idx]; } GBool BufStream::isBinary(GBool last) { return str->isBinary(gTrue); } //------------------------------------------------------------------------ // FixedLengthEncoder //------------------------------------------------------------------------ FixedLengthEncoder::FixedLengthEncoder(Stream *strA, int lengthA): FilterStream(strA) { length = lengthA; count = 0; } FixedLengthEncoder::~FixedLengthEncoder() { if (str->isEncoder()) delete str; } void FixedLengthEncoder::reset() { str->reset(); count = 0; } int FixedLengthEncoder::getChar() { if (length >= 0 && count >= length) return EOF; ++count; return str->getChar(); } int FixedLengthEncoder::lookChar() { if (length >= 0 && count >= length) return EOF; return str->getChar(); } GBool FixedLengthEncoder::isBinary(GBool last) { return str->isBinary(gTrue); } //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ ASCIIHexEncoder::ASCIIHexEncoder(Stream *strA): FilterStream(strA) { bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } ASCIIHexEncoder::~ASCIIHexEncoder() { if (str->isEncoder()) { delete str; } } void ASCIIHexEncoder::reset() { str->reset(); bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } GBool ASCIIHexEncoder::fillBuf() { static const char *hex = "0123456789abcdef"; int c; if (eof) { return gFalse; } bufPtr = bufEnd = buf; if ((c = str->getChar()) == EOF) { *bufEnd++ = '>'; eof = gTrue; } else { if (lineLen >= 64) { *bufEnd++ = '\n'; lineLen = 0; } *bufEnd++ = hex[(c >> 4) & 0x0f]; *bufEnd++ = hex[c & 0x0f]; lineLen += 2; } return gTrue; } //------------------------------------------------------------------------ // ASCII85Encoder //------------------------------------------------------------------------ ASCII85Encoder::ASCII85Encoder(Stream *strA): FilterStream(strA) { bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } ASCII85Encoder::~ASCII85Encoder() { if (str->isEncoder()) delete str; } void ASCII85Encoder::reset() { str->reset(); bufPtr = bufEnd = buf; lineLen = 0; eof = gFalse; } GBool ASCII85Encoder::fillBuf() { Guint t; char buf1[5]; int c0, c1, c2, c3; int n, i; if (eof) { return gFalse; } c0 = str->getChar(); c1 = str->getChar(); c2 = str->getChar(); c3 = str->getChar(); bufPtr = bufEnd = buf; if (c3 == EOF) { if (c0 == EOF) { n = 0; t = 0; } else { if (c1 == EOF) { n = 1; t = c0 << 24; } else if (c2 == EOF) { n = 2; t = (c0 << 24) | (c1 << 16); } else { n = 3; t = (c0 << 24) | (c1 << 16) | (c2 << 8); } for (i = 4; i >= 0; --i) { buf1[i] = (char)(t % 85 + 0x21); t /= 85; } for (i = 0; i <= n; ++i) { *bufEnd++ = buf1[i]; if (++lineLen == 65) { *bufEnd++ = '\n'; lineLen = 0; } } } *bufEnd++ = '~'; *bufEnd++ = '>'; eof = gTrue; } else { t = (c0 << 24) | (c1 << 16) | (c2 << 8) | c3; if (t == 0) { *bufEnd++ = 'z'; if (++lineLen == 65) { *bufEnd++ = '\n'; lineLen = 0; } } else { for (i = 4; i >= 0; --i) { buf1[i] = (char)(t % 85 + 0x21); t /= 85; } for (i = 0; i <= 4; ++i) { *bufEnd++ = buf1[i]; if (++lineLen == 65) { *bufEnd++ = '\n'; lineLen = 0; } } } } return gTrue; } //------------------------------------------------------------------------ // RunLengthEncoder //------------------------------------------------------------------------ RunLengthEncoder::RunLengthEncoder(Stream *strA): FilterStream(strA) { bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } RunLengthEncoder::~RunLengthEncoder() { if (str->isEncoder()) delete str; } void RunLengthEncoder::reset() { str->reset(); bufPtr = bufEnd = nextEnd = buf; eof = gFalse; } // // When fillBuf finishes, buf[] looks like this: // +-----+--------------+-----------------+-- // + tag | ... data ... | next 0, 1, or 2 | // +-----+--------------+-----------------+-- // ^ ^ ^ // bufPtr bufEnd nextEnd // GBool RunLengthEncoder::fillBuf() { int c, c1, c2; int n; // already hit EOF? if (eof) return gFalse; // grab two bytes if (nextEnd < bufEnd + 1) { if ((c1 = str->getChar()) == EOF) { eof = gTrue; return gFalse; } } else { c1 = bufEnd[0] & 0xff; } if (nextEnd < bufEnd + 2) { if ((c2 = str->getChar()) == EOF) { eof = gTrue; buf[0] = 0; buf[1] = c1; bufPtr = buf; bufEnd = &buf[2]; return gTrue; } } else { c2 = bufEnd[1] & 0xff; } // check for repeat c = 0; // make gcc happy if (c1 == c2) { n = 2; while (n < 128 && (c = str->getChar()) == c1) ++n; buf[0] = (char)(257 - n); buf[1] = c1; bufEnd = &buf[2]; if (c == EOF) { eof = gTrue; } else if (n < 128) { buf[2] = c; nextEnd = &buf[3]; } else { nextEnd = bufEnd; } // get up to 128 chars } else { buf[1] = c1; buf[2] = c2; n = 2; while (n < 128) { if ((c = str->getChar()) == EOF) { eof = gTrue; break; } ++n; buf[n] = c; if (buf[n] == buf[n-1]) break; } if (buf[n] == buf[n-1]) { buf[0] = (char)(n-2-1); bufEnd = &buf[n-1]; nextEnd = &buf[n+1]; } else { buf[0] = (char)(n-1); bufEnd = nextEnd = &buf[n+1]; } } bufPtr = buf; return gTrue; } xpdf-3.03/xpdf/Decrypt.h0000644000076400007640000000545711622305345014452 0ustar dereknderekn//======================================================================== // // Decrypt.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef DECRYPT_H #define DECRYPT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "GString.h" #include "Object.h" #include "Stream.h" //------------------------------------------------------------------------ // Decrypt //------------------------------------------------------------------------ class Decrypt { public: // Generate a file key. The buffer must have space for at // least 16 bytes. Checks and then // and returns true if either is correct. Sets if // the owner password was correct. Either or both of the passwords // may be NULL, which is treated as an empty string. static GBool makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, GString *ownerEnc, GString *userEnc, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, Guchar *fileKey, GBool encryptMetadata, GBool *ownerPasswordOk); private: static GBool makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *userPassword, Guchar *fileKey, GBool encryptMetadata); }; //------------------------------------------------------------------------ // DecryptStream //------------------------------------------------------------------------ struct DecryptRC4State { Guchar state[256]; Guchar x, y; int buf; }; struct DecryptAESState { Guint w[44]; Guchar state[16]; Guchar cbc[16]; Guchar buf[16]; int bufIdx; }; struct DecryptAES256State { Guint w[60]; Guchar state[16]; Guchar cbc[16]; Guchar buf[16]; int bufIdx; }; class DecryptStream: public FilterStream { public: DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, int keyLength, int objNum, int objGen); virtual ~DecryptStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual GBool isBinary(GBool last); virtual Stream *getUndecodedStream() { return this; } private: CryptAlgorithm algo; int objKeyLength; Guchar objKey[32]; union { DecryptRC4State rc4; DecryptAESState aes; DecryptAES256State aes256; } state; }; //------------------------------------------------------------------------ extern void rc4InitKey(Guchar *key, int keyLen, Guchar *state); extern Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); extern void md5(Guchar *msg, int msgLen, Guchar *digest); #endif xpdf-3.03/xpdf/CharTypes.h0000644000076400007640000000101611622305345014725 0ustar dereknderekn//======================================================================== // // CharTypes.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CHARTYPES_H #define CHARTYPES_H // Unicode character. typedef unsigned int Unicode; // Character ID for CID character collections. typedef unsigned int CID; // This is large enough to hold any of the following: // - 8-bit char code // - 16-bit CID // - Unicode typedef unsigned int CharCode; #endif xpdf-3.03/xpdf/config.h0000644000076400007640000000600411622305345014272 0ustar dereknderekn//======================================================================== // // config.h // // Copyright 1996-2011 Glyph & Cog, LLC // //======================================================================== #ifndef CONFIG_H #define CONFIG_H //------------------------------------------------------------------------ // version //------------------------------------------------------------------------ // xpdf version #define xpdfVersion "3.03" #define xpdfVersionNum 3.03 #define xpdfMajorVersion 3 #define xpdfMinorVersion 3 #define xpdfUpdateVersion 0 #define xpdfMajorVersionStr "3" #define xpdfMinorVersionStr "3" #define xpdfUpdateVersionStr "0" // supported PDF version #define supportedPDFVersionStr "1.7" #define supportedPDFVersionNum 1.7 // copyright notice #define xpdfCopyright "Copyright 1996-2011 Glyph & Cog, LLC" // Windows resource file stuff #define winxpdfVersion "WinXpdf 3.03" #define xpdfCopyrightAmp "Copyright 1996-2011 Glyph && Cog, LLC" //------------------------------------------------------------------------ // paper size //------------------------------------------------------------------------ // default paper size (in points) for PostScript output #ifdef A4_PAPER #define defPaperWidth 595 // ISO A4 (210x297 mm) #define defPaperHeight 842 #else #define defPaperWidth 612 // American letter (8.5x11") #define defPaperHeight 792 #endif //------------------------------------------------------------------------ // config file (xpdfrc) path //------------------------------------------------------------------------ // user config file name, relative to the user's home directory #if defined(VMS) || defined(WIN32) #define xpdfUserConfigFile "xpdfrc" #else #define xpdfUserConfigFile ".xpdfrc" #endif // system config file name (set via the configure script) #ifdef SYSTEM_XPDFRC #define xpdfSysConfigFile SYSTEM_XPDFRC #else // under Windows, we get the directory with the executable and then // append this file name #define xpdfSysConfigFile "xpdfrc" #endif //------------------------------------------------------------------------ // X-related constants //------------------------------------------------------------------------ // default maximum size of color cube to allocate #define defaultRGBCube 5 //------------------------------------------------------------------------ // popen //------------------------------------------------------------------------ #if defined(_MSC_VER) || defined(__BORLANDC__) #define popen _popen #define pclose _pclose #endif #if defined(VMS) || defined(VMCMS) || defined(DOS) || defined(OS2) || defined(__EMX__) || defined(WIN32) || defined(__DJGPP__) || defined(MACOS) #define POPEN_READ_MODE "rb" #else #define POPEN_READ_MODE "r" #endif //------------------------------------------------------------------------ // Win32 stuff //------------------------------------------------------------------------ #ifdef CDECL #undef CDECL #endif #if defined(_MSC_VER) || defined(__BORLANDC__) #define CDECL __cdecl #else #define CDECL #endif #endif xpdf-3.03/xpdf/GfxFont.cc0000644000076400007640000015444411622305345014552 0ustar dereknderekn//======================================================================== // // GfxFont.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include #if HAVE_STD_SORT #include #endif #include "gmem.h" #include "Error.h" #include "Object.h" #include "Dict.h" #include "GlobalParams.h" #include "CMap.h" #include "CharCodeToUnicode.h" #include "FontEncodingTables.h" #include "BuiltinFontTables.h" #include "FoFiIdentifier.h" #include "FoFiType1.h" #include "FoFiType1C.h" #include "FoFiTrueType.h" #include "GfxFont.h" //------------------------------------------------------------------------ struct Base14FontMapEntry { const char *altName; const char *base14Name; }; static Base14FontMapEntry base14FontMap[] = { { "Arial", "Helvetica" }, { "Arial,Bold", "Helvetica-Bold" }, { "Arial,BoldItalic", "Helvetica-BoldOblique" }, { "Arial,Italic", "Helvetica-Oblique" }, { "Arial-Bold", "Helvetica-Bold" }, { "Arial-BoldItalic", "Helvetica-BoldOblique" }, { "Arial-BoldItalicMT", "Helvetica-BoldOblique" }, { "Arial-BoldMT", "Helvetica-Bold" }, { "Arial-Italic", "Helvetica-Oblique" }, { "Arial-ItalicMT", "Helvetica-Oblique" }, { "ArialMT", "Helvetica" }, { "Courier", "Courier" }, { "Courier,Bold", "Courier-Bold" }, { "Courier,BoldItalic", "Courier-BoldOblique" }, { "Courier,Italic", "Courier-Oblique" }, { "Courier-Bold", "Courier-Bold" }, { "Courier-BoldOblique", "Courier-BoldOblique" }, { "Courier-Oblique", "Courier-Oblique" }, { "CourierNew", "Courier" }, { "CourierNew,Bold", "Courier-Bold" }, { "CourierNew,BoldItalic", "Courier-BoldOblique" }, { "CourierNew,Italic", "Courier-Oblique" }, { "CourierNew-Bold", "Courier-Bold" }, { "CourierNew-BoldItalic", "Courier-BoldOblique" }, { "CourierNew-Italic", "Courier-Oblique" }, { "CourierNewPS-BoldItalicMT", "Courier-BoldOblique" }, { "CourierNewPS-BoldMT", "Courier-Bold" }, { "CourierNewPS-ItalicMT", "Courier-Oblique" }, { "CourierNewPSMT", "Courier" }, { "Helvetica", "Helvetica" }, { "Helvetica,Bold", "Helvetica-Bold" }, { "Helvetica,BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica,Italic", "Helvetica-Oblique" }, { "Helvetica-Bold", "Helvetica-Bold" }, { "Helvetica-BoldItalic", "Helvetica-BoldOblique" }, { "Helvetica-BoldOblique", "Helvetica-BoldOblique" }, { "Helvetica-Italic", "Helvetica-Oblique" }, { "Helvetica-Oblique", "Helvetica-Oblique" }, { "Symbol", "Symbol" }, { "Symbol,Bold", "Symbol" }, { "Symbol,BoldItalic", "Symbol" }, { "Symbol,Italic", "Symbol" }, { "Times-Bold", "Times-Bold" }, { "Times-BoldItalic", "Times-BoldItalic" }, { "Times-Italic", "Times-Italic" }, { "Times-Roman", "Times-Roman" }, { "TimesNewRoman", "Times-Roman" }, { "TimesNewRoman,Bold", "Times-Bold" }, { "TimesNewRoman,BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman,Italic", "Times-Italic" }, { "TimesNewRoman-Bold", "Times-Bold" }, { "TimesNewRoman-BoldItalic", "Times-BoldItalic" }, { "TimesNewRoman-Italic", "Times-Italic" }, { "TimesNewRomanPS", "Times-Roman" }, { "TimesNewRomanPS-Bold", "Times-Bold" }, { "TimesNewRomanPS-BoldItalic", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldItalicMT", "Times-BoldItalic" }, { "TimesNewRomanPS-BoldMT", "Times-Bold" }, { "TimesNewRomanPS-Italic", "Times-Italic" }, { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, { "TimesNewRomanPSMT", "Times-Roman" }, { "TimesNewRomanPSMT,Bold", "Times-Bold" }, { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, { "TimesNewRomanPSMT,Italic", "Times-Italic" }, { "ZapfDingbats", "ZapfDingbats" } }; //------------------------------------------------------------------------ // index: {fixed:0, sans-serif:4, serif:8} + bold*2 + italic // NB: must be in same order as psSubstFonts in PSOutputDev.cc static const char *base14SubstFonts[14] = { "Courier", "Courier-Oblique", "Courier-Bold", "Courier-BoldOblique", "Helvetica", "Helvetica-Oblique", "Helvetica-Bold", "Helvetica-BoldOblique", "Times-Roman", "Times-Italic", "Times-Bold", "Times-BoldItalic", // the last two are never used for substitution "Symbol", "ZapfDingbats" }; //------------------------------------------------------------------------ static int readFromStream(void *data) { return ((Stream *)data)->getChar(); } //------------------------------------------------------------------------ // GfxFontLoc //------------------------------------------------------------------------ GfxFontLoc::GfxFontLoc() { path = NULL; fontNum = 0; encoding = NULL; substIdx = -1; } GfxFontLoc::~GfxFontLoc() { if (path) { delete path; } if (encoding) { delete encoding; } } //------------------------------------------------------------------------ // GfxFont //------------------------------------------------------------------------ GfxFont *GfxFont::makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict) { GString *nameA; Ref embFontIDA; GfxFontType typeA; GfxFont *font; Object obj1; // get base font name nameA = NULL; fontDict->lookup("BaseFont", &obj1); if (obj1.isName()) { nameA = new GString(obj1.getName()); } obj1.free(); // get embedded font ID and font type typeA = getFontType(xref, fontDict, &embFontIDA); // create the font object font = NULL; if (typeA < fontCIDType0) { font = new Gfx8BitFont(xref, tagA, idA, nameA, typeA, embFontIDA, fontDict); } else { font = new GfxCIDFont(xref, tagA, idA, nameA, typeA, embFontIDA, fontDict); } return font; } GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA) { ok = gFalse; tag = new GString(tagA); id = idA; name = nameA; type = typeA; embFontID = embFontIDA; embFontName = NULL; } GfxFont::~GfxFont() { delete tag; if (name) { delete name; } if (embFontName) { delete embFontName; } } // This function extracts three pieces of information: // 1. the "expected" font type, i.e., the font type implied by // Font.Subtype, DescendantFont.Subtype, and // FontDescriptor.FontFile3.Subtype // 2. the embedded font object ID // 3. the actual font type - determined by examining the embedded font // if there is one, otherwise equal to the expected font type // If the expected and actual font types don't match, a warning // message is printed. The expected font type is not used for // anything else. GfxFontType GfxFont::getFontType(XRef *xref, Dict *fontDict, Ref *embID) { GfxFontType t, expectedType; FoFiIdentifierType fft; Dict *fontDict2; Object subtype, fontDesc, obj1, obj2, obj3, obj4; GBool isType0, err; t = fontUnknownType; embID->num = embID->gen = -1; err = gFalse; fontDict->lookup("Subtype", &subtype); expectedType = fontUnknownType; isType0 = gFalse; if (subtype.isName("Type1") || subtype.isName("MMType1")) { expectedType = fontType1; } else if (subtype.isName("Type1C")) { expectedType = fontType1C; } else if (subtype.isName("Type3")) { expectedType = fontType3; } else if (subtype.isName("TrueType")) { expectedType = fontTrueType; } else if (subtype.isName("Type0")) { isType0 = gTrue; } else { error(errSyntaxWarning, -1, "Unknown font type: '{0:s}'", subtype.isName() ? subtype.getName() : "???"); } subtype.free(); fontDict2 = fontDict; if (fontDict->lookup("DescendantFonts", &obj1)->isArray()) { if (obj1.arrayGetLength() == 0) { error(errSyntaxWarning, -1, "Empty DescendantFonts array in font"); obj2.initNull(); } else if (obj1.arrayGet(0, &obj2)->isDict()) { if (!isType0) { error(errSyntaxWarning, -1, "Non-CID font with DescendantFonts array"); } fontDict2 = obj2.getDict(); fontDict2->lookup("Subtype", &subtype); if (subtype.isName("CIDFontType0")) { if (isType0) { expectedType = fontCIDType0; } } else if (subtype.isName("CIDFontType2")) { if (isType0) { expectedType = fontCIDType2; } } subtype.free(); } } else { obj2.initNull(); } if (fontDict2->lookup("FontDescriptor", &fontDesc)->isDict()) { if (fontDesc.dictLookupNF("FontFile", &obj3)->isRef()) { *embID = obj3.getRef(); if (expectedType != fontType1) { err = gTrue; } } obj3.free(); if (embID->num == -1 && fontDesc.dictLookupNF("FontFile2", &obj3)->isRef()) { *embID = obj3.getRef(); if (isType0) { expectedType = fontCIDType2; } else if (expectedType != fontTrueType) { err = gTrue; } } obj3.free(); if (embID->num == -1 && fontDesc.dictLookupNF("FontFile3", &obj3)->isRef()) { *embID = obj3.getRef(); if (obj3.fetch(xref, &obj4)->isStream()) { obj4.streamGetDict()->lookup("Subtype", &subtype); if (subtype.isName("Type1")) { if (expectedType != fontType1) { err = gTrue; expectedType = isType0 ? fontCIDType0 : fontType1; } } else if (subtype.isName("Type1C")) { if (expectedType == fontType1) { expectedType = fontType1C; } else if (expectedType != fontType1C) { err = gTrue; expectedType = isType0 ? fontCIDType0C : fontType1C; } } else if (subtype.isName("TrueType")) { if (expectedType != fontTrueType) { err = gTrue; expectedType = isType0 ? fontCIDType2 : fontTrueType; } } else if (subtype.isName("CIDFontType0C")) { if (expectedType == fontCIDType0) { expectedType = fontCIDType0C; } else { err = gTrue; expectedType = isType0 ? fontCIDType0C : fontType1C; } } else if (subtype.isName("OpenType")) { if (expectedType == fontTrueType) { expectedType = fontTrueTypeOT; } else if (expectedType == fontType1) { expectedType = fontType1COT; } else if (expectedType == fontCIDType0) { expectedType = fontCIDType0COT; } else if (expectedType == fontCIDType2) { expectedType = fontCIDType2OT; } else { err = gTrue; } } else { error(errSyntaxError, -1, "Unknown font type '{0:s}'", subtype.isName() ? subtype.getName() : "???"); } subtype.free(); } obj4.free(); } obj3.free(); } fontDesc.free(); t = fontUnknownType; if (embID->num >= 0) { obj3.initRef(embID->num, embID->gen); obj3.fetch(xref, &obj4); if (obj4.isStream()) { obj4.streamReset(); fft = FoFiIdentifier::identifyStream(&readFromStream, obj4.getStream()); obj4.streamClose(); switch (fft) { case fofiIdType1PFA: case fofiIdType1PFB: t = fontType1; break; case fofiIdCFF8Bit: t = isType0 ? fontCIDType0C : fontType1C; break; case fofiIdCFFCID: t = fontCIDType0C; break; case fofiIdTrueType: case fofiIdTrueTypeCollection: t = isType0 ? fontCIDType2 : fontTrueType; break; case fofiIdOpenTypeCFF8Bit: t = isType0 ? fontCIDType0COT : fontType1COT; break; case fofiIdOpenTypeCFFCID: t = fontCIDType0COT; break; default: error(errSyntaxError, -1, "Embedded font file may be invalid"); break; } } obj4.free(); obj3.free(); } if (t == fontUnknownType) { t = expectedType; } if (t != expectedType) { err = gTrue; } if (err) { error(errSyntaxWarning, -1, "Mismatch between font type and embedded font file"); } obj2.free(); obj1.free(); return t; } void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { Object obj1, obj2, obj3, obj4; double t; int i; // assume Times-Roman by default (for substitution purposes) flags = fontSerif; missingWidth = 0; if (fontDict->lookup("FontDescriptor", &obj1)->isDict()) { // get flags if (obj1.dictLookup("Flags", &obj2)->isInt()) { flags = obj2.getInt(); } obj2.free(); // get name obj1.dictLookup("FontName", &obj2); if (obj2.isName()) { embFontName = new GString(obj2.getName()); } obj2.free(); // look for MissingWidth obj1.dictLookup("MissingWidth", &obj2); if (obj2.isNum()) { missingWidth = obj2.getNum(); } obj2.free(); // get Ascent and Descent obj1.dictLookup("Ascent", &obj2); if (obj2.isNum()) { t = 0.001 * obj2.getNum(); // some broken font descriptors specify a negative ascent if (t < 0) { t = -t; } // some broken font descriptors set ascent and descent to 0; // others set it to ridiculous values (e.g., 32768) if (t != 0 && t < 3) { ascent = t; } } obj2.free(); obj1.dictLookup("Descent", &obj2); if (obj2.isNum()) { t = 0.001 * obj2.getNum(); // some broken font descriptors specify a positive descent if (t > 0) { t = -t; } // some broken font descriptors set ascent and descent to 0 if (t != 0 && t > -3) { descent = t; } } obj2.free(); // font FontBBox if (obj1.dictLookup("FontBBox", &obj2)->isArray()) { for (i = 0; i < 4 && i < obj2.arrayGetLength(); ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { fontBBox[i] = 0.001 * obj3.getNum(); } obj3.free(); } } obj2.free(); } obj1.free(); } CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits, CharCodeToUnicode *ctu) { GString *buf; Object obj1; int c; if (!fontDict->lookup("ToUnicode", &obj1)->isStream()) { obj1.free(); return NULL; } buf = new GString(); obj1.streamReset(); while ((c = obj1.streamGetChar()) != EOF) { buf->append(c); } obj1.streamClose(); obj1.free(); if (ctu) { ctu->mergeCMap(buf, nBits); } else { ctu = CharCodeToUnicode::parseCMap(buf, nBits); } delete buf; return ctu; } GfxFontLoc *GfxFont::locateFont(XRef *xref, GBool ps) { GfxFontLoc *fontLoc; SysFontType sysFontType; GString *path, *base14Name, *substName; PSFontParam16 *psFont16; Object refObj, embFontObj; int substIdx, fontNum; GBool embed; if (type == fontType3) { return NULL; } //----- embedded font if (embFontID.num >= 0) { embed = gTrue; refObj.initRef(embFontID.num, embFontID.gen); refObj.fetch(xref, &embFontObj); if (!embFontObj.isStream()) { error(errSyntaxError, -1, "Embedded font object is wrong type"); embed = gFalse; } embFontObj.free(); refObj.free(); if (embed) { if (ps) { switch (type) { case fontType1: case fontType1C: case fontType1COT: embed = globalParams->getPSEmbedType1(); break; case fontTrueType: case fontTrueTypeOT: embed = globalParams->getPSEmbedTrueType(); break; case fontCIDType0C: case fontCIDType0COT: embed = globalParams->getPSEmbedCIDPostScript(); break; case fontCIDType2: case fontCIDType2OT: embed = globalParams->getPSEmbedCIDTrueType(); break; default: break; } } if (embed) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocEmbedded; fontLoc->fontType = type; fontLoc->embFontID = embFontID; return fontLoc; } } } //----- PS passthrough if (ps && !isCIDFont() && globalParams->getPSFontPassthrough()) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontType1; fontLoc->path = name->copy(); return fontLoc; } //----- PS resident Base-14 font if (ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontType1; fontLoc->path = new GString(((Gfx8BitFont *)this)->base14->base14Name); return fontLoc; } //----- external font file (fontFile, fontDir) if ((path = globalParams->findFontFile(name))) { if ((fontLoc = getExternalFont(path, isCIDFont()))) { return fontLoc; } } //----- external font file for Base-14 font if (!ps && !isCIDFont() && ((Gfx8BitFont *)this)->base14) { base14Name = new GString(((Gfx8BitFont *)this)->base14->base14Name); if ((path = globalParams->findFontFile(base14Name))) { if ((fontLoc = getExternalFont(path, gFalse))) { delete base14Name; return fontLoc; } } delete base14Name; } //----- system font if ((path = globalParams->findSystemFontFile(name, &sysFontType, &fontNum))) { if (isCIDFont()) { if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontCIDType2; fontLoc->path = path; fontLoc->fontNum = fontNum; return fontLoc; } } else { if (sysFontType == sysFontTTF || sysFontType == sysFontTTC) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontTrueType; fontLoc->path = path; return fontLoc; } else if (sysFontType == sysFontPFA || sysFontType == sysFontPFB) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontType1; fontLoc->path = path; fontLoc->fontNum = fontNum; return fontLoc; } } delete path; } if (!isCIDFont()) { //----- 8-bit PS resident font if (ps) { if ((path = globalParams->getPSResidentFont(name))) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontType1; fontLoc->path = path; return fontLoc; } } //----- 8-bit font substitution if (flags & fontFixedWidth) { substIdx = 0; } else if (flags & fontSerif) { substIdx = 8; } else { substIdx = 4; } if (isBold()) { substIdx += 2; } if (isItalic()) { substIdx += 1; } substName = new GString(base14SubstFonts[substIdx]); if (ps) { error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", base14SubstFonts[substIdx], name); fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontType1; fontLoc->path = substName; fontLoc->substIdx = substIdx; return fontLoc; } else { path = globalParams->findFontFile(substName); delete substName; if (path) { if ((fontLoc = getExternalFont(path, gFalse))) { error(errSyntaxWarning, -1, "Substituting font '{0:s}' for '{1:t}'", base14SubstFonts[substIdx], name); fontLoc->substIdx = substIdx; return fontLoc; } } } // failed to find a substitute font return NULL; } //----- 16-bit PS resident font if (ps && ((psFont16 = globalParams->getPSResidentFont16( name, ((GfxCIDFont *)this)->getWMode())))) { fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontCIDType0; // this is not used fontLoc->path = psFont16->psFontName->copy(); fontLoc->encoding = psFont16->encoding->copy(); fontLoc->wMode = psFont16->wMode; return fontLoc; } if (ps && ((psFont16 = globalParams->getPSResidentFontCC( ((GfxCIDFont *)this)->getCollection(), ((GfxCIDFont *)this)->getWMode())))) { error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", psFont16->psFontName, name); fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocResident; fontLoc->fontType = fontCIDType0; // this is not used fontLoc->path = psFont16->psFontName->copy(); fontLoc->encoding = psFont16->encoding->copy(); fontLoc->wMode = psFont16->wMode; return fontLoc; } //----- CID font substitution if ((path = globalParams->findCCFontFile( ((GfxCIDFont *)this)->getCollection()))) { if ((fontLoc = getExternalFont(path, gTrue))) { error(errSyntaxWarning, -1, "Substituting font '{0:t}' for '{1:t}'", fontLoc->path, name); return fontLoc; } } // failed to find a substitute font return NULL; } GfxFontLoc *GfxFont::locateBase14Font(GString *base14Name) { GString *path; path = globalParams->findFontFile(base14Name); if (!path) { return NULL; } return getExternalFont(path, gFalse); } GfxFontLoc *GfxFont::getExternalFont(GString *path, GBool cid) { FoFiIdentifierType fft; GfxFontType fontType; GfxFontLoc *fontLoc; fft = FoFiIdentifier::identifyFile(path->getCString()); switch (fft) { case fofiIdType1PFA: case fofiIdType1PFB: fontType = fontType1; break; case fofiIdCFF8Bit: fontType = fontType1C; break; case fofiIdCFFCID: fontType = fontCIDType0C; break; case fofiIdTrueType: case fofiIdTrueTypeCollection: fontType = cid ? fontCIDType2 : fontTrueType; break; case fofiIdOpenTypeCFF8Bit: fontType = fontType1COT; break; case fofiIdOpenTypeCFFCID: fontType = fontCIDType0COT; break; case fofiIdUnknown: case fofiIdError: default: fontType = fontUnknownType; break; } if (fontType == fontUnknownType || (cid ? (fontType < fontCIDType0) : (fontType >= fontCIDType0))) { delete path; return NULL; } fontLoc = new GfxFontLoc(); fontLoc->locType = gfxFontLocExternal; fontLoc->fontType = fontType; fontLoc->path = path; return fontLoc; } char *GfxFont::readEmbFontFile(XRef *xref, int *len) { char *buf; Object obj1, obj2; Stream *str; int c; int size, i; obj1.initRef(embFontID.num, embFontID.gen); obj1.fetch(xref, &obj2); if (!obj2.isStream()) { error(errSyntaxError, -1, "Embedded font file is not a stream"); obj2.free(); obj1.free(); embFontID.num = -1; return NULL; } str = obj2.getStream(); buf = NULL; i = size = 0; str->reset(); while ((c = str->getChar()) != EOF) { if (i == size) { if (size > INT_MAX - 4096) { error(errSyntaxError, -1, "Embedded font file is too large"); break; } size += 4096; buf = (char *)grealloc(buf, size); } buf[i++] = c; } *len = i; str->close(); obj2.free(); obj1.free(); return buf; } //------------------------------------------------------------------------ // Gfx8BitFont //------------------------------------------------------------------------ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict): GfxFont(tagA, idA, nameA, typeA, embFontIDA) { GString *name2; BuiltinFont *builtinFont; const char **baseEnc; GBool baseEncFromFontFile; char *buf; int len; FoFiType1 *ffT1; FoFiType1C *ffT1C; int code, code2; char *charName; GBool missing, hex; Unicode toUnicode[256]; CharCodeToUnicode *utu, *ctu2; Unicode uBuf[8]; double mul; int firstChar, lastChar; Gushort w; Object obj1, obj2, obj3; int n, i, a, b, m; ctu = NULL; // do font name substitution for various aliases of the Base 14 font // names base14 = NULL; if (name) { name2 = name->copy(); i = 0; while (i < name2->getLength()) { if (name2->getChar(i) == ' ') { name2->del(i); } else { ++i; } } a = 0; b = sizeof(base14FontMap) / sizeof(Base14FontMapEntry); // invariant: base14FontMap[a].altName <= name2 < base14FontMap[b].altName while (b - a > 1) { m = (a + b) / 2; if (name2->cmp(base14FontMap[m].altName) >= 0) { a = m; } else { b = m; } } if (!name2->cmp(base14FontMap[a].altName)) { base14 = &base14FontMap[a]; } delete name2; } // is it a built-in font? builtinFont = NULL; if (base14) { for (i = 0; i < nBuiltinFonts; ++i) { if (!strcmp(base14->base14Name, builtinFonts[i].name)) { builtinFont = &builtinFonts[i]; break; } } } // default ascent/descent values if (builtinFont) { ascent = 0.001 * builtinFont->ascent; descent = 0.001 * builtinFont->descent; fontBBox[0] = 0.001 * builtinFont->bbox[0]; fontBBox[1] = 0.001 * builtinFont->bbox[1]; fontBBox[2] = 0.001 * builtinFont->bbox[2]; fontBBox[3] = 0.001 * builtinFont->bbox[3]; } else { ascent = 0.95; descent = -0.35; fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; } // get info from font descriptor readFontDescriptor(xref, fontDict); // for non-embedded fonts, don't trust the ascent/descent/bbox // values from the font descriptor if (builtinFont && embFontID.num < 0) { ascent = 0.001 * builtinFont->ascent; descent = 0.001 * builtinFont->descent; fontBBox[0] = 0.001 * builtinFont->bbox[0]; fontBBox[1] = 0.001 * builtinFont->bbox[1]; fontBBox[2] = 0.001 * builtinFont->bbox[2]; fontBBox[3] = 0.001 * builtinFont->bbox[3]; } // get font matrix fontMat[0] = fontMat[3] = 1; fontMat[1] = fontMat[2] = fontMat[4] = fontMat[5] = 0; if (fontDict->lookup("FontMatrix", &obj1)->isArray()) { for (i = 0; i < 6 && i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { fontMat[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); // get Type 3 bounding box, font definition, and resources if (type == fontType3) { if (fontDict->lookup("FontBBox", &obj1)->isArray()) { for (i = 0; i < 4 && i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { fontBBox[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); if (!fontDict->lookup("CharProcs", &charProcs)->isDict()) { error(errSyntaxError, -1, "Missing or invalid CharProcs dictionary in Type 3 font"); charProcs.free(); } if (!fontDict->lookup("Resources", &resources)->isDict()) { resources.free(); } } //----- build the font encoding ----- // Encodings start with a base encoding, which can come from // (in order of priority): // 1. FontDict.Encoding or FontDict.Encoding.BaseEncoding // - MacRoman / MacExpert / WinAnsi / Standard // 2. embedded or external font file // 3. default: // - builtin --> builtin encoding // - TrueType --> WinAnsiEncoding // - others --> StandardEncoding // and then add a list of differences (if any) from // FontDict.Encoding.Differences. // check FontDict for base encoding hasEncoding = gFalse; usesMacRomanEnc = gFalse; baseEnc = NULL; baseEncFromFontFile = gFalse; fontDict->lookup("Encoding", &obj1); if (obj1.isDict()) { obj1.dictLookup("BaseEncoding", &obj2); if (obj2.isName("MacRomanEncoding")) { hasEncoding = gTrue; usesMacRomanEnc = gTrue; baseEnc = macRomanEncoding; } else if (obj2.isName("MacExpertEncoding")) { hasEncoding = gTrue; baseEnc = macExpertEncoding; } else if (obj2.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } obj2.free(); } else if (obj1.isName("MacRomanEncoding")) { hasEncoding = gTrue; usesMacRomanEnc = gTrue; baseEnc = macRomanEncoding; } else if (obj1.isName("MacExpertEncoding")) { hasEncoding = gTrue; baseEnc = macExpertEncoding; } else if (obj1.isName("WinAnsiEncoding")) { hasEncoding = gTrue; baseEnc = winAnsiEncoding; } // check embedded font file for base encoding // (only for Type 1 fonts - trying to get an encoding out of a // TrueType font is a losing proposition) ffT1 = NULL; ffT1C = NULL; buf = NULL; if (type == fontType1 && embFontID.num >= 0) { if ((buf = readEmbFontFile(xref, &len))) { if ((ffT1 = FoFiType1::make(buf, len))) { if (ffT1->getName()) { if (embFontName) { delete embFontName; } embFontName = new GString(ffT1->getName()); } if (!baseEnc) { baseEnc = (const char **)ffT1->getEncoding(); baseEncFromFontFile = gTrue; } } gfree(buf); } } else if (type == fontType1C && embFontID.num >= 0) { if ((buf = readEmbFontFile(xref, &len))) { if ((ffT1C = FoFiType1C::make(buf, len))) { if (ffT1C->getName()) { if (embFontName) { delete embFontName; } embFontName = new GString(ffT1C->getName()); } if (!baseEnc) { baseEnc = (const char **)ffT1C->getEncoding(); baseEncFromFontFile = gTrue; } } gfree(buf); } } // get default base encoding if (!baseEnc) { if (builtinFont && embFontID.num < 0) { baseEnc = builtinFont->defaultBaseEnc; hasEncoding = gTrue; } else if (type == fontTrueType) { baseEnc = winAnsiEncoding; } else { baseEnc = standardEncoding; } } // copy the base encoding for (i = 0; i < 256; ++i) { enc[i] = (char *)baseEnc[i]; if ((encFree[i] = baseEncFromFontFile) && enc[i]) { enc[i] = copyString(baseEnc[i]); } } // some Type 1C font files have empty encodings, which can break the // T1C->T1 conversion (since the 'seac' operator depends on having // the accents in the encoding), so we fill in any gaps from // StandardEncoding if (type == fontType1C && embFontID.num >= 0 && baseEncFromFontFile) { for (i = 0; i < 256; ++i) { if (!enc[i] && standardEncoding[i]) { enc[i] = (char *)standardEncoding[i]; encFree[i] = gFalse; } } } // merge differences into encoding if (obj1.isDict()) { obj1.dictLookup("Differences", &obj2); if (obj2.isArray()) { hasEncoding = gTrue; code = 0; for (i = 0; i < obj2.arrayGetLength(); ++i) { obj2.arrayGet(i, &obj3); if (obj3.isInt()) { code = obj3.getInt(); } else if (obj3.isName()) { if (code >= 0 && code < 256) { if (encFree[code]) { gfree(enc[code]); } enc[code] = copyString(obj3.getName()); encFree[code] = gTrue; } ++code; } else { error(errSyntaxError, -1, "Wrong type in font encoding resource differences ({0:s})", obj3.getTypeName()); } obj3.free(); } } obj2.free(); } obj1.free(); if (ffT1) { delete ffT1; } if (ffT1C) { delete ffT1C; } //----- build the mapping to Unicode ----- // pass 1: use the name-to-Unicode mapping table missing = hex = gFalse; for (code = 0; code < 256; ++code) { if ((charName = enc[code])) { if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) && strcmp(charName, ".notdef")) { // if it wasn't in the name-to-Unicode table, check for a // name that looks like 'Axx' or 'xx', where 'A' is any letter // and 'xx' is two hex digits if ((strlen(charName) == 3 && isalpha(charName[0]) && isxdigit(charName[1]) && isxdigit(charName[2]) && ((charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F') || (charName[2] >= 'a' && charName[2] <= 'f') || (charName[2] >= 'A' && charName[2] <= 'F'))) || (strlen(charName) == 2 && isxdigit(charName[0]) && isxdigit(charName[1]) && ((charName[0] >= 'a' && charName[0] <= 'f') || (charName[0] >= 'A' && charName[0] <= 'F') || (charName[1] >= 'a' && charName[1] <= 'f') || (charName[1] >= 'A' && charName[1] <= 'F')))) { hex = gTrue; } missing = gTrue; } } else { toUnicode[code] = 0; } } // pass 2: try to fill in the missing chars, looking for names of // any of the following forms: // - 'xx' // - 'Axx' // - 'nn' // - 'Ann' // - 'ABnn' // - 'unixxxx' (possibly followed by garbage - some Arabic files // use 'uni0628.medi', etc.) // where 'A' and 'B' are any letters, 'xx' is two hex digits, 'xxxx' // is four hex digits, and 'nn' is 2-4 decimal digits if (missing && globalParams->getMapNumericCharNames()) { for (code = 0; code < 256; ++code) { if ((charName = enc[code]) && !toUnicode[code] && strcmp(charName, ".notdef")) { n = (int)strlen(charName); code2 = -1; if (hex && n == 3 && isalpha(charName[0]) && isxdigit(charName[1]) && isxdigit(charName[2])) { sscanf(charName+1, "%x", &code2); } else if (hex && n == 2 && isxdigit(charName[0]) && isxdigit(charName[1])) { sscanf(charName, "%x", &code2); } else if (!hex && n >= 2 && n <= 4 && isdigit(charName[0]) && isdigit(charName[1])) { code2 = atoi(charName); } else if (n >= 3 && n <= 5 && isdigit(charName[1]) && isdigit(charName[2])) { code2 = atoi(charName+1); } else if (n >= 4 && n <= 6 && isdigit(charName[2]) && isdigit(charName[3])) { code2 = atoi(charName+2); } else if (n >= 7 && charName[0] == 'u' && charName[1] == 'n' && charName[2] == 'i' && isxdigit(charName[3]) && isxdigit(charName[4]) && isxdigit(charName[5]) && isxdigit(charName[6])) { sscanf(charName + 3, "%x", &code2); } if (code2 >= 0 && code2 <= 0xffff) { toUnicode[code] = (Unicode)code2; } } } // if the 'mapUnknownCharNames' flag is set, do a simple pass-through // mapping for unknown character names } else if (missing && globalParams->getMapUnknownCharNames()) { for (code = 0; code < 256; ++code) { if (!toUnicode[code]) { toUnicode[code] = code; } } } // construct the char code -> Unicode mapping object ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode); // merge in a ToUnicode CMap, if there is one -- this overwrites // existing entries in ctu, i.e., the ToUnicode CMap takes // precedence, but the other encoding info is allowed to fill in any // holes readToUnicodeCMap(fontDict, 8, ctu); // look for a Unicode-to-Unicode mapping if (name && (utu = globalParams->getUnicodeToUnicode(name))) { for (i = 0; i < 256; ++i) { toUnicode[i] = 0; } ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode); for (i = 0; i < 256; ++i) { n = ctu->mapToUnicode((CharCode)i, uBuf, 8); if (n >= 1) { n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); if (n >= 1) { ctu2->setMapping((CharCode)i, uBuf, n); } } } utu->decRefCnt(); delete ctu; ctu = ctu2; } //----- get the character widths ----- // initialize all widths for (code = 0; code < 256; ++code) { widths[code] = missingWidth * 0.001; } // use widths from font dict, if present fontDict->lookup("FirstChar", &obj1); firstChar = obj1.isInt() ? obj1.getInt() : 0; obj1.free(); if (firstChar < 0 || firstChar > 255) { firstChar = 0; } fontDict->lookup("LastChar", &obj1); lastChar = obj1.isInt() ? obj1.getInt() : 255; obj1.free(); if (lastChar < 0 || lastChar > 255) { lastChar = 255; } mul = (type == fontType3) ? fontMat[0] : 0.001; fontDict->lookup("Widths", &obj1); if (obj1.isArray()) { flags |= fontFixedWidth; if (obj1.arrayGetLength() < lastChar - firstChar + 1) { lastChar = firstChar + obj1.arrayGetLength() - 1; } for (code = firstChar; code <= lastChar; ++code) { obj1.arrayGet(code - firstChar, &obj2); if (obj2.isNum()) { widths[code] = obj2.getNum() * mul; if (fabs(widths[code] - widths[firstChar]) > 0.00001) { flags &= ~fontFixedWidth; } } obj2.free(); } // use widths from built-in font } else if (builtinFont) { // this is a kludge for broken PDF files that encode char 32 // as .notdef if (builtinFont->widths->getWidth("space", &w)) { widths[32] = 0.001 * w; } for (code = 0; code < 256; ++code) { if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { widths[code] = 0.001 * w; } } // couldn't find widths -- use defaults } else { // this is technically an error -- the Widths entry is required // for all but the Base-14 fonts -- but certain PDF generators // apparently don't include widths for Arial and TimesNewRoman if (isFixedWidth()) { i = 0; } else if (isSerif()) { i = 8; } else { i = 4; } if (isBold()) { i += 2; } if (isItalic()) { i += 1; } builtinFont = builtinFontSubst[i]; // this is a kludge for broken PDF files that encode char 32 // as .notdef if (builtinFont->widths->getWidth("space", &w)) { widths[32] = 0.001 * w; } for (code = 0; code < 256; ++code) { if (enc[code] && builtinFont->widths->getWidth(enc[code], &w)) { widths[code] = 0.001 * w; } } } obj1.free(); ok = gTrue; } Gfx8BitFont::~Gfx8BitFont() { int i; for (i = 0; i < 256; ++i) { if (encFree[i] && enc[i]) { gfree(enc[i]); } } ctu->decRefCnt(); if (charProcs.isDict()) { charProcs.free(); } if (resources.isDict()) { resources.free(); } } int Gfx8BitFont::getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, double *dx, double *dy, double *ox, double *oy) { CharCode c; *code = c = (CharCode)(*s & 0xff); *uLen = ctu->mapToUnicode(c, u, uSize); *dx = widths[c]; *dy = *ox = *oy = 0; return 1; } CharCodeToUnicode *Gfx8BitFont::getToUnicode() { ctu->incRefCnt(); return ctu; } int *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { int *map; int cmapPlatform, cmapEncoding; int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; GBool useMacRoman, useUnicode; char *charName; Unicode u; int code, i, n; map = (int *)gmallocn(256, sizeof(int)); for (i = 0; i < 256; ++i) { map[i] = 0; } // To match up with the Adobe-defined behaviour, we choose a cmap // like this: // 1. If the PDF font has an encoding: // 1a. If the PDF font specified MacRomanEncoding and the // TrueType font has a Macintosh Roman cmap, use it, and // reverse map the char names through MacRomanEncoding to // get char codes. // 1b. If the PDF font is not symbolic or the PDF font is not // embedded, and the TrueType font has a Microsoft Unicode // cmap or a non-Microsoft Unicode cmap, use it, and use the // Unicode indexes, not the char codes. // 1c. If the PDF font is symbolic and the TrueType font has a // Microsoft Symbol cmap, use it, and use char codes // directly (possibly with an offset of 0xf000). // 1d. If the TrueType font has a Macintosh Roman cmap, use it, // as in case 1a. // 2. If the PDF font does not have an encoding or the PDF font is // symbolic: // 2a. If the TrueType font has a Macintosh Roman cmap, use it, // and use char codes directly (possibly with an offset of // 0xf000). // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, // and use char codes directly (possible with an offset of // 0xf000). // 3. If none of these rules apply, use the first cmap and hope for // the best (this shouldn't happen). unicodeCmap = macRomanCmap = msSymbolCmap = -1; for (i = 0; i < ff->getNumCmaps(); ++i) { cmapPlatform = ff->getCmapPlatform(i); cmapEncoding = ff->getCmapEncoding(i); if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) { unicodeCmap = i; } else if (cmapPlatform == 1 && cmapEncoding == 0) { macRomanCmap = i; } else if (cmapPlatform == 3 && cmapEncoding == 0) { msSymbolCmap = i; } } cmap = 0; useMacRoman = gFalse; useUnicode = gFalse; if (hasEncoding) { if (usesMacRomanEnc && macRomanCmap >= 0) { cmap = macRomanCmap; useMacRoman = gTrue; } else if ((!(flags & fontSymbolic) || embFontID.num < 0) && unicodeCmap >= 0) { cmap = unicodeCmap; useUnicode = gTrue; } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) { cmap = msSymbolCmap; } else if ((flags & fontSymbolic) && macRomanCmap >= 0) { cmap = macRomanCmap; } else if (macRomanCmap >= 0) { cmap = macRomanCmap; useMacRoman = gTrue; } } else { if (msSymbolCmap >= 0) { cmap = msSymbolCmap; } else if (macRomanCmap >= 0) { cmap = macRomanCmap; } } // reverse map the char names through MacRomanEncoding, then map the // char codes through the cmap if (useMacRoman) { for (i = 0; i < 256; ++i) { if ((charName = enc[i])) { if ((code = globalParams->getMacRomanCharCode(charName))) { map[i] = ff->mapCodeToGID(cmap, code); } } else { map[i] = -1; } } // map Unicode through the cmap } else if (useUnicode) { for (i = 0; i < 256; ++i) { if (((charName = enc[i]) && (u = globalParams->mapNameToUnicode(charName))) || (n = ctu->mapToUnicode((CharCode)i, &u, 1))) { map[i] = ff->mapCodeToGID(cmap, u); } else { map[i] = -1; } } // map the char codes through the cmap, possibly with an offset of // 0xf000 } else { for (i = 0; i < 256; ++i) { if (!(map[i] = ff->mapCodeToGID(cmap, i))) { map[i] = ff->mapCodeToGID(cmap, 0xf000 + i); } } } // try the TrueType 'post' table to handle any unmapped characters for (i = 0; i < 256; ++i) { if (map[i] <= 0 && (charName = enc[i])) { map[i] = ff->mapNameToGID(charName); } } return map; } Dict *Gfx8BitFont::getCharProcs() { return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL; } Object *Gfx8BitFont::getCharProc(int code, Object *proc) { if (enc[code] && charProcs.isDict()) { charProcs.dictLookup(enc[code], proc); } else { proc->initNull(); } return proc; } Dict *Gfx8BitFont::getResources() { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } //------------------------------------------------------------------------ // GfxCIDFont //------------------------------------------------------------------------ #if HAVE_STD_SORT struct cmpWidthExcepFunctor { bool operator()(const GfxFontCIDWidthExcep &w1, const GfxFontCIDWidthExcep &w2) { return w1.first < w2.first; } }; struct cmpWidthExcepVFunctor { bool operator()(const GfxFontCIDWidthExcepV &w1, const GfxFontCIDWidthExcepV &w2) { return w1.first < w2.first; } }; #else // HAVE_STD_SORT static int CDECL cmpWidthExcep(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcep *)w1)->first - ((GfxFontCIDWidthExcep *)w2)->first; } static int CDECL cmpWidthExcepV(const void *w1, const void *w2) { return ((GfxFontCIDWidthExcepV *)w1)->first - ((GfxFontCIDWidthExcepV *)w2)->first; } #endif GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict): GfxFont(tagA, idA, nameA, typeA, embFontIDA) { Dict *desFontDict; Object desFontDictObj; Object obj1, obj2, obj3, obj4, obj5, obj6; CharCodeToUnicode *utu; CharCode c; Unicode uBuf[8]; int c1, c2; int excepsSize, i, j, k, n; ascent = 0.95; descent = -0.35; fontBBox[0] = fontBBox[1] = fontBBox[2] = fontBBox[3] = 0; collection = NULL; cMap = NULL; ctu = NULL; ctuUsesCharCode = gTrue; widths.defWidth = 1.0; widths.defHeight = -1.0; widths.defVY = 0.880; widths.exceps = NULL; widths.nExceps = 0; widths.excepsV = NULL; widths.nExcepsV = 0; cidToGID = NULL; cidToGIDLen = 0; // get the descendant font if (!fontDict->lookup("DescendantFonts", &obj1)->isArray() || obj1.arrayGetLength() == 0) { error(errSyntaxError, -1, "Missing or empty DescendantFonts entry in Type 0 font"); obj1.free(); goto err1; } if (!obj1.arrayGet(0, &desFontDictObj)->isDict()) { error(errSyntaxError, -1, "Bad descendant font in Type 0 font"); goto err2; } obj1.free(); desFontDict = desFontDictObj.getDict(); // get info from font descriptor readFontDescriptor(xref, desFontDict); //----- encoding info ----- // char collection if (!desFontDict->lookup("CIDSystemInfo", &obj1)->isDict()) { error(errSyntaxError, -1, "Missing CIDSystemInfo dictionary in Type 0 descendant font"); goto err2; } obj1.dictLookup("Registry", &obj2); obj1.dictLookup("Ordering", &obj3); if (!obj2.isString() || !obj3.isString()) { error(errSyntaxError, -1, "Invalid CIDSystemInfo dictionary in Type 0 descendant font"); goto err3; } collection = obj2.getString()->copy()->append('-')->append(obj3.getString()); obj3.free(); obj2.free(); obj1.free(); // look for a ToUnicode CMap if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) { ctuUsesCharCode = gFalse; // use an identity mapping for the "Adobe-Identity" and // "Adobe-UCS" collections if (!collection->cmp("Adobe-Identity") || !collection->cmp("Adobe-UCS")) { ctu = CharCodeToUnicode::makeIdentityMapping(); // look for a user-supplied .cidToUnicode file } else if (!(ctu = globalParams->getCIDToUnicode(collection))) { error(errSyntaxError, -1, "Unknown character collection '{0:t}'", collection); } } // look for a Unicode-to-Unicode mapping if (name && (utu = globalParams->getUnicodeToUnicode(name))) { if (ctu) { for (c = 0; c < ctu->getLength(); ++c) { n = ctu->mapToUnicode(c, uBuf, 8); if (n >= 1) { n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8); if (n >= 1) { ctu->setMapping(c, uBuf, n); } } } utu->decRefCnt(); } else { ctu = utu; } } // encoding (i.e., CMap) if (fontDict->lookup("Encoding", &obj1)->isNull()) { error(errSyntaxError, -1, "Missing Encoding entry in Type 0 font"); goto err2; } if (!(cMap = CMap::parse(NULL, collection, &obj1))) { goto err2; } obj1.free(); // CIDToGIDMap // (the PDF spec only allows these for TrueType fonts, but Acrobat // apparently also allows them for OpenType CFF fonts) if (type == fontCIDType2 || type == fontCIDType0COT) { desFontDict->lookup("CIDToGIDMap", &obj1); if (obj1.isStream()) { cidToGIDLen = 0; i = 64; cidToGID = (int *)gmallocn(i, sizeof(int)); obj1.streamReset(); while ((c1 = obj1.streamGetChar()) != EOF && (c2 = obj1.streamGetChar()) != EOF) { if (cidToGIDLen == i) { i *= 2; cidToGID = (int *)greallocn(cidToGID, i, sizeof(int)); } cidToGID[cidToGIDLen++] = (c1 << 8) + c2; } } else if (!obj1.isName("Identity") && !obj1.isNull()) { error(errSyntaxError, -1, "Invalid CIDToGIDMap entry in CID font"); } obj1.free(); } //----- character metrics ----- // default char width if (desFontDict->lookup("DW", &obj1)->isInt()) { widths.defWidth = obj1.getInt() * 0.001; } obj1.free(); // char width exceptions if (desFontDict->lookup("W", &obj1)->isArray()) { excepsSize = 0; i = 0; while (i + 1 < obj1.arrayGetLength()) { obj1.arrayGet(i, &obj2); obj1.arrayGet(i + 1, &obj3); if (obj2.isInt() && obj3.isInt() && i + 2 < obj1.arrayGetLength()) { if (obj1.arrayGet(i + 2, &obj4)->isNum()) { if (widths.nExceps == excepsSize) { excepsSize += 16; widths.exceps = (GfxFontCIDWidthExcep *) greallocn(widths.exceps, excepsSize, sizeof(GfxFontCIDWidthExcep)); } widths.exceps[widths.nExceps].first = obj2.getInt(); widths.exceps[widths.nExceps].last = obj3.getInt(); widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; ++widths.nExceps; } else { error(errSyntaxError, -1, "Bad widths array in Type 0 font"); } obj4.free(); i += 3; } else if (obj2.isInt() && obj3.isArray()) { if (widths.nExceps + obj3.arrayGetLength() > excepsSize) { excepsSize = (widths.nExceps + obj3.arrayGetLength() + 15) & ~15; widths.exceps = (GfxFontCIDWidthExcep *) greallocn(widths.exceps, excepsSize, sizeof(GfxFontCIDWidthExcep)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); ++k) { if (obj3.arrayGet(k, &obj4)->isNum()) { widths.exceps[widths.nExceps].first = j; widths.exceps[widths.nExceps].last = j; widths.exceps[widths.nExceps].width = obj4.getNum() * 0.001; ++j; ++widths.nExceps; } else { error(errSyntaxError, -1, "Bad widths array in Type 0 font"); } obj4.free(); } i += 2; } else { error(errSyntaxError, -1, "Bad widths array in Type 0 font"); ++i; } obj3.free(); obj2.free(); } #if HAVE_STD_SORT std::sort(widths.exceps, widths.exceps + widths.nExceps, cmpWidthExcepFunctor()); #else qsort(widths.exceps, widths.nExceps, sizeof(GfxFontCIDWidthExcep), &cmpWidthExcep); #endif } obj1.free(); // default metrics for vertical font if (desFontDict->lookup("DW2", &obj1)->isArray() && obj1.arrayGetLength() == 2) { if (obj1.arrayGet(0, &obj2)->isNum()) { widths.defVY = obj2.getNum() * 0.001; } obj2.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { widths.defHeight = obj2.getNum() * 0.001; } obj2.free(); } obj1.free(); // char metric exceptions for vertical font if (desFontDict->lookup("W2", &obj1)->isArray()) { excepsSize = 0; i = 0; while (i + 1 < obj1.arrayGetLength()) { obj1.arrayGet(i, &obj2); obj1.arrayGet(i+ 1, &obj3); if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) { if (obj1.arrayGet(i + 2, &obj4)->isNum() && obj1.arrayGet(i + 3, &obj5)->isNum() && obj1.arrayGet(i + 4, &obj6)->isNum()) { if (widths.nExcepsV == excepsSize) { excepsSize += 16; widths.excepsV = (GfxFontCIDWidthExcepV *) greallocn(widths.excepsV, excepsSize, sizeof(GfxFontCIDWidthExcepV)); } widths.excepsV[widths.nExcepsV].first = obj2.getInt(); widths.excepsV[widths.nExcepsV].last = obj3.getInt(); widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001; widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001; widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001; ++widths.nExcepsV; } else { error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font"); } obj6.free(); obj5.free(); obj4.free(); i += 5; } else if (obj2.isInt() && obj3.isArray()) { if (widths.nExcepsV + obj3.arrayGetLength() / 3 > excepsSize) { excepsSize = (widths.nExcepsV + obj3.arrayGetLength() / 3 + 15) & ~15; widths.excepsV = (GfxFontCIDWidthExcepV *) greallocn(widths.excepsV, excepsSize, sizeof(GfxFontCIDWidthExcepV)); } j = obj2.getInt(); for (k = 0; k < obj3.arrayGetLength(); k += 3) { if (obj3.arrayGet(k, &obj4)->isNum() && obj3.arrayGet(k+1, &obj5)->isNum() && obj3.arrayGet(k+2, &obj6)->isNum()) { widths.excepsV[widths.nExcepsV].first = j; widths.excepsV[widths.nExcepsV].last = j; widths.excepsV[widths.nExcepsV].height = obj4.getNum() * 0.001; widths.excepsV[widths.nExcepsV].vx = obj5.getNum() * 0.001; widths.excepsV[widths.nExcepsV].vy = obj6.getNum() * 0.001; ++j; ++widths.nExcepsV; } else { error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font"); } obj6.free(); obj5.free(); obj4.free(); } i += 2; } else { error(errSyntaxError, -1, "Bad widths (W2) array in Type 0 font"); ++i; } obj3.free(); obj2.free(); } #if HAVE_STD_SORT std::sort(widths.excepsV, widths.excepsV + widths.nExcepsV, cmpWidthExcepVFunctor()); #else qsort(widths.excepsV, widths.nExcepsV, sizeof(GfxFontCIDWidthExcepV), &cmpWidthExcepV); #endif } obj1.free(); desFontDictObj.free(); ok = gTrue; return; err3: obj3.free(); obj2.free(); err2: obj1.free(); desFontDictObj.free(); err1:; } GfxCIDFont::~GfxCIDFont() { if (collection) { delete collection; } if (cMap) { cMap->decRefCnt(); } if (ctu) { ctu->decRefCnt(); } gfree(widths.exceps); gfree(widths.excepsV); if (cidToGID) { gfree(cidToGID); } } int GfxCIDFont::getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, double *dx, double *dy, double *ox, double *oy) { CID cid; CharCode c; double w, h, vx, vy; int n, a, b, m; if (!cMap) { *code = 0; *uLen = 0; *dx = *dy = 0; return 1; } *code = (CharCode)(cid = cMap->getCID(s, len, &c, &n)); if (ctu) { *uLen = ctu->mapToUnicode(ctuUsesCharCode ? c : cid, u, uSize); } else { *uLen = 0; } if (!*uLen && uSize >= 1 && globalParams->getMapUnknownCharNames()) { u[0] = *code; *uLen = 1; } // horizontal if (cMap->getWMode() == 0) { w = widths.defWidth; h = vx = vy = 0; if (widths.nExceps > 0 && cid >= widths.exceps[0].first) { a = 0; b = widths.nExceps; // invariant: widths.exceps[a].first <= cid < widths.exceps[b].first while (b - a > 1) { m = (a + b) / 2; if (widths.exceps[m].first <= cid) { a = m; } else { b = m; } } if (cid <= widths.exceps[a].last) { w = widths.exceps[a].width; } } // vertical } else { w = 0; h = widths.defHeight; vx = widths.defWidth / 2; vy = widths.defVY; if (widths.nExcepsV > 0 && cid >= widths.excepsV[0].first) { a = 0; b = widths.nExcepsV; // invariant: widths.excepsV[a].first <= cid < widths.excepsV[b].first while (b - a > 1) { m = (a + b) / 2; if (widths.excepsV[m].last <= cid) { a = m; } else { b = m; } } if (cid <= widths.excepsV[a].last) { h = widths.excepsV[a].height; vx = widths.excepsV[a].vx; vy = widths.excepsV[a].vy; } } } *dx = w; *dy = h; *ox = vx; *oy = vy; return n; } int GfxCIDFont::getWMode() { return cMap ? cMap->getWMode() : 0; } CharCodeToUnicode *GfxCIDFont::getToUnicode() { if (ctu) { ctu->incRefCnt(); } return ctu; } GString *GfxCIDFont::getCollection() { return cMap ? cMap->getCollection() : (GString *)NULL; } //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) { int i; Object obj1, obj2; Ref r; numFonts = fontDict->getLength(); fonts = (GfxFont **)gmallocn(numFonts, sizeof(GfxFont *)); for (i = 0; i < numFonts; ++i) { fontDict->getValNF(i, &obj1); obj1.fetch(xref, &obj2); if (obj2.isDict()) { if (obj1.isRef()) { r = obj1.getRef(); } else { // no indirect reference for this font, so invent a unique one // (legal generation numbers are five digits, so any 6-digit // number would be safe) r.num = i; if (fontDictRef) { r.gen = 100000 + fontDictRef->num; } else { r.gen = 999999; } } fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i), r, obj2.getDict()); if (fonts[i] && !fonts[i]->isOk()) { delete fonts[i]; fonts[i] = NULL; } } else { error(errSyntaxError, -1, "font resource is not a dictionary"); fonts[i] = NULL; } obj1.free(); obj2.free(); } } GfxFontDict::~GfxFontDict() { int i; for (i = 0; i < numFonts; ++i) { if (fonts[i]) { delete fonts[i]; } } gfree(fonts); } GfxFont *GfxFontDict::lookup(char *tag) { int i; for (i = 0; i < numFonts; ++i) { if (fonts[i] && fonts[i]->matches(tag)) { return fonts[i]; } } return NULL; } xpdf-3.03/xpdf/pdffonts.cc0000644000076400007640000001647111622305345015017 0ustar dereknderekn//======================================================================== // // pdffonts.cc // // Copyright 2001-2007 Glyph & Cog, LLC // //======================================================================== #include #include #include #include #include #include #include #include "parseargs.h" #include "GString.h" #include "gmem.h" #include "GlobalParams.h" #include "Error.h" #include "Object.h" #include "Dict.h" #include "GfxFont.h" #include "Annot.h" #include "PDFDoc.h" #include "config.h" // NB: this must match the definition of GfxFontType in GfxFont.h. static const char *fontTypeNames[] = { "unknown", "Type 1", "Type 1C", "Type 1C (OT)", "Type 3", "TrueType", "TrueType (OT)", "CID Type 0", "CID Type 0C", "CID Type 0C (OT)", "CID TrueType", "CID TrueType (OT)" }; static void scanFonts(Dict *resDict, PDFDoc *doc); static void scanFont(GfxFont *font, PDFDoc *doc); static int firstPage = 1; static int lastPage = 0; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to examine"}, {"-l", argInt, &lastPage, 0, "last page to examine"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; static Ref *fonts; static int fontsLen; static int fontsSize; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; GString *ownerPW, *userPW; GBool ok; Page *page; Dict *resDict; Annots *annots; Object obj1, obj2; int pg, i; int exitCode; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || argc != 2 || printVersion || printHelp) { fprintf(stderr, "pdffonts version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdffonts", "", argDesc); } goto err0; } fileName = new GString(argv[1]); // read config file globalParams = new GlobalParams(cfgFileName); // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err1; } // get page range if (firstPage < 1) { firstPage = 1; } if (lastPage < 1 || lastPage > doc->getNumPages()) { lastPage = doc->getNumPages(); } // scan the fonts printf("name type emb sub uni object ID\n"); printf("------------------------------------ ----------------- --- --- --- ---------\n"); fonts = NULL; fontsLen = fontsSize = 0; for (pg = firstPage; pg <= lastPage; ++pg) { page = doc->getCatalog()->getPage(pg); if ((resDict = page->getResourceDict())) { scanFonts(resDict, doc); } annots = new Annots(doc, page->getAnnots(&obj1)); obj1.free(); for (i = 0; i < annots->getNumAnnots(); ++i) { if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { obj1.streamGetDict()->lookup("Resources", &obj2); if (obj2.isDict()) { scanFonts(obj2.getDict(), doc); } obj2.free(); } obj1.free(); } delete annots; } exitCode = 0; // clean up gfree(fonts); err1: delete doc; delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } static void scanFonts(Dict *resDict, PDFDoc *doc) { Object obj1, obj2, xObjDict, xObj, resObj; Ref r; GfxFontDict *gfxFontDict; GfxFont *font; int i; // scan the fonts in this resource dictionary gfxFontDict = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { obj1.fetch(doc->getXRef(), &obj2); if (obj2.isDict()) { r = obj1.getRef(); gfxFontDict = new GfxFontDict(doc->getXRef(), &r, obj2.getDict()); } obj2.free(); } else if (obj1.isDict()) { gfxFontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict()); } if (gfxFontDict) { for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { if ((font = gfxFontDict->getFont(i))) { scanFont(font, doc); } } delete gfxFontDict; } obj1.free(); // recursively scan any resource dictionaries in objects in this // resource dictionary resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { xObjDict.dictGetVal(i, &xObj); if (xObj.isStream()) { xObj.streamGetDict()->lookup("Resources", &resObj); if (resObj.isDict()) { scanFonts(resObj.getDict(), doc); } resObj.free(); } xObj.free(); } } xObjDict.free(); } static void scanFont(GfxFont *font, PDFDoc *doc) { Ref fontRef, embRef; Object fontObj, toUnicodeObj; GString *name; GBool emb, subset, hasToUnicode; int i; fontRef = *font->getID(); // check for an already-seen font for (i = 0; i < fontsLen; ++i) { if (fontRef.num == fonts[i].num && fontRef.gen == fonts[i].gen) { return; } } // font name name = font->getName(); // check for an embedded font if (font->getType() == fontType3) { emb = gTrue; } else { emb = font->getEmbeddedFontID(&embRef); } // look for a ToUnicode map hasToUnicode = gFalse; if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) { hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream(); toUnicodeObj.free(); } fontObj.free(); // check for a font subset name: capital letters followed by a '+' // sign subset = gFalse; if (name) { for (i = 0; i < name->getLength(); ++i) { if (name->getChar(i) < 'A' || name->getChar(i) > 'Z') { break; } } subset = i > 0 && i < name->getLength() && name->getChar(i) == '+'; } // print the font info printf("%-36s %-17s %-3s %-3s %-3s", name ? name->getCString() : "[none]", fontTypeNames[font->getType()], emb ? "yes" : "no", subset ? "yes" : "no", hasToUnicode ? "yes" : "no"); if (fontRef.gen >= 100000) { printf(" [none]\n"); } else { printf(" %6d %2d\n", fontRef.num, fontRef.gen); } // add this font to the list if (fontsLen == fontsSize) { if (fontsSize <= INT_MAX - 32) { fontsSize += 32; } else { // let greallocn throw an exception fontsSize = -1; } fonts = (Ref *)greallocn(fonts, fontsSize, sizeof(Ref)); } fonts[fontsLen++] = *font->getID(); } xpdf-3.03/xpdf/PSOutputDev.h0000644000076400007640000003617411622305345015242 0ustar dereknderekn//======================================================================== // // PSOutputDev.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PSOUTPUTDEV_H #define PSOUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "config.h" #include "Object.h" #include "GlobalParams.h" #include "OutputDev.h" class GHash; class PDFDoc; class XRef; class Function; class GfxPath; class GfxFont; class GfxColorSpace; class GfxSeparationColorSpace; class PDFRectangle; struct PST1FontName; struct PSFont8Info; struct PSFont16Enc; class PSOutCustomColor; class PSOutputDev; //------------------------------------------------------------------------ // PSOutputDev //------------------------------------------------------------------------ enum PSOutMode { psModePS, psModeEPS, psModeForm }; enum PSFileType { psFile, // write to file psPipe, // write to pipe psStdout, // write to stdout psGeneric // write to a generic stream }; enum PSOutCustomCodeLocation { psOutCustomDocSetup, psOutCustomPageSetup }; typedef void (*PSOutputFunc)(void *stream, const char *data, int len); typedef GString *(*PSOutCustomCodeCbk)(PSOutputDev *psOut, PSOutCustomCodeLocation loc, int n, void *data); class PSOutputDev: public OutputDev { public: // Open a PostScript output file, and write the prolog. PSOutputDev(char *fileName, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA = 0, int imgLLYA = 0, int imgURXA = 0, int imgURYA = 0, GBool manualCtrlA = gFalse, PSOutCustomCodeCbk customCodeCbkA = NULL, void *customCodeCbkDataA = NULL); // Open a PSOutputDev that will write to a generic stream. PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA = 0, int imgLLYA = 0, int imgURXA = 0, int imgURYA = 0, GBool manualCtrlA = gFalse, PSOutCustomCodeCbk customCodeCbkA = NULL, void *customCodeCbkDataA = NULL); // Destructor -- writes the trailer and closes the file. virtual ~PSOutputDev(); // Check if file was successfully created. virtual GBool isOk() { return ok; } //---- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gFalse; } // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gFalse; } // Does this device use tilingPatternFill()? If this returns false, // tiling pattern fills will be reduced to a series of other drawing // operations. virtual GBool useTilingPatternFill() { return gTrue; } // Does this device use functionShadedFill(), axialShadedFill(), and // radialShadedFill()? If this returns false, these shaded fills // will be reduced to a series of other drawing operations. virtual GBool useShadedFills() { return level >= psLevel2; } // Does this device use drawForm()? If this returns false, // form-type XObjects will be interpreted (i.e., unrolled). virtual GBool useDrawForm() { return preload; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } //----- header/trailer (used only if manualCtrl is true) // Write the document-level header. void writeHeader(int firstPage, int lastPage, PDFRectangle *mediaBox, PDFRectangle *cropBox, int pageRotate); // Write the Xpdf procset. void writeXpdfProcset(); // Write the document-level setup. void writeDocSetup(Catalog *catalog, int firstPage, int lastPage); // Write the trailer for the current page. void writePageTrailer(); // Write the document trailer. void writeTrailer(); //----- initialization and control // Check to see if a page slice should be displayed. If this // returns false, the page display is aborted. Typically, an // OutputDev will use some alternate means to display the page // before returning false. virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Start a page. virtual void startPage(int pageNum, GfxState *state); // End a page. virtual void endPage(); //----- save/restore graphics state virtual void saveState(GfxState *state); virtual void restoreState(GfxState *state); //----- update graphics state virtual void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32); virtual void updateLineDash(GfxState *state); virtual void updateFlatness(GfxState *state); virtual void updateLineJoin(GfxState *state); virtual void updateLineCap(GfxState *state); virtual void updateMiterLimit(GfxState *state); virtual void updateLineWidth(GfxState *state); virtual void updateFillColorSpace(GfxState *state); virtual void updateStrokeColorSpace(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); virtual void updateFillOverprint(GfxState *state); virtual void updateStrokeOverprint(GfxState *state); virtual void updateTransfer(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); virtual void updateTextMat(GfxState *state); virtual void updateCharSpace(GfxState *state); virtual void updateRender(GfxState *state); virtual void updateRise(GfxState *state); virtual void updateWordSpace(GfxState *state); virtual void updateHorizScaling(GfxState *state); virtual void updateTextPos(GfxState *state); virtual void updateTextShift(GfxState *state, double shift); virtual void saveTextPos(GfxState *state); virtual void restoreTextPos(GfxState *state); //----- path painting virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep); virtual GBool functionShadedFill(GfxState *state, GfxFunctionShading *shading); virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading); virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading); //----- path clipping virtual void clip(GfxState *state); virtual void eoClip(GfxState *state); virtual void clipToStrokePath(GfxState *state); //----- text drawing virtual void drawString(GfxState *state, GString *s); virtual void endTextObject(GfxState *state); //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); #if OPI_SUPPORT //----- OPI functions virtual void opiBegin(GfxState *state, Dict *opiDict); virtual void opiEnd(GfxState *state, Dict *opiDict); #endif //----- Type 3 font operators virtual void type3D0(GfxState *state, double wx, double wy); virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury); //----- form XObjects virtual void drawForm(Ref ref); //----- PostScript XObjects virtual void psXObject(Stream *psStream, Stream *level1Stream); //----- miscellaneous void setOffset(double x, double y) { tx0 = x; ty0 = y; } void setScale(double x, double y) { xScale0 = x; yScale0 = y; } void setRotate(int rotateA) { rotate0 = rotateA; } void setClip(double llx, double lly, double urx, double ury) { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; } void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), void *data) { underlayCbk = cbk; underlayCbkData = data; } void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), void *data) { overlayCbk = cbk; overlayCbkData = data; } void writePSChar(char c); void writePS(const char *s); void writePSFmt(const char *fmt, ...); void writePSString(GString *s); void writePSName(const char *s); private: void init(PSOutputFunc outputFuncA, void *outputStreamA, PSFileType fileTypeA, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA); void setupResources(Dict *resDict); void setupFonts(Dict *resDict); void setupFont(GfxFont *font, Dict *parentResDict); void setupEmbeddedType1Font(Ref *id, GString *psName); void setupExternalType1Font(GString *fileName, GString *psName); void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName); void setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName); void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName); void setupExternalTrueTypeFont(GfxFont *font, GString *fileName, GString *psName); void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName); void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, GBool needVerticalMetrics); void setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, GString *psName, GBool needVerticalMetrics); void setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName); void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict); GString *makePSFontName(GfxFont *font, Ref *id); void setupImages(Dict *resDict); void setupImage(Ref id, Stream *str, GBool mask); void setupForms(Dict *resDict); void setupForm(Ref id, Object *strObj); void addProcessColor(double c, double m, double y, double k); void addCustomColor(GfxSeparationColorSpace *sepCS); void doPath(GfxPath *path); void doImageL1(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len); void doImageL1Sep(GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len); void doImageL2(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len, int *maskColors, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); void doImageL3(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len, int *maskColors, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); void dumpColorSpaceL2(GfxColorSpace *colorSpace, GBool genXform, GBool updateColors, GBool map01); #if OPI_SUPPORT void opiBegin20(GfxState *state, Dict *dict); void opiBegin13(GfxState *state, Dict *dict); void opiTransform(GfxState *state, double x0, double y0, double *x1, double *y1); GBool getFileSpec(Object *fileSpec, Object *fileName); #endif void cvtFunction(Function *func); GString *filterPSName(GString *name); void writePSTextLine(GString *s); PSLevel level; // PostScript level (1, 2, separation) PSOutMode mode; // PostScript mode (PS, EPS, form) int paperWidth; // width of paper, in pts int paperHeight; // height of paper, in pts GBool paperMatch; // true if paper size is set to match each page int imgLLX, imgLLY, // imageable area, in pts imgURX, imgURY; GBool preload; // load all images into memory, and // predefine forms PSOutputFunc outputFunc; void *outputStream; PSFileType fileType; // file / pipe / stdout GBool manualCtrl; int seqPage; // current sequential page number void (*underlayCbk)(PSOutputDev *psOut, void *data); void *underlayCbkData; void (*overlayCbk)(PSOutputDev *psOut, void *data); void *overlayCbkData; GString *(*customCodeCbk)(PSOutputDev *psOut, PSOutCustomCodeLocation loc, int n, void *data); void *customCodeCbkData; PDFDoc *doc; XRef *xref; // the xref table for this PDF file Ref *fontIDs; // list of object IDs of all used fonts int fontIDLen; // number of entries in fontIDs array int fontIDSize; // size of fontIDs array GHash *fontNames; // all used font names PST1FontName *t1FontNames; // font names for Type 1/1C fonts int t1FontNameLen; // number of entries in t1FontNames array int t1FontNameSize; // size of t1FontNames array PSFont8Info *font8Info; // info for 8-bit fonts int font8InfoLen; // number of entries in font8Info array int font8InfoSize; // size of font8Info array PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts int font16EncLen; // number of entries in font16Enc array int font16EncSize; // size of font16Enc array Ref *imgIDs; // list of image IDs for in-memory images int imgIDLen; // number of entries in imgIDs array int imgIDSize; // size of imgIDs array Ref *formIDs; // list of IDs for predefined forms int formIDLen; // number of entries in formIDs array int formIDSize; // size of formIDs array GList *xobjStack; // stack of XObject dicts currently being // processed int numSaves; // current number of gsaves int numTilingPatterns; // current number of nested tiling patterns int nextFunc; // next unique number to use for a function GList *paperSizes; // list of used paper sizes, if paperMatch // is true [PSOutPaperSize] double tx0, ty0; // global translation double xScale0, yScale0; // global scaling int rotate0; // rotation angle (0, 90, 180, 270) double clipLLX0, clipLLY0, clipURX0, clipURY0; double tx, ty; // global translation for current page double xScale, yScale; // global scaling for current page int rotate; // rotation angle for current page double epsX1, epsY1, // EPS bounding box (unrotated) epsX2, epsY2; GString *embFontList; // resource comments for embedded fonts int processColors; // used process colors PSOutCustomColor // used custom colors *customColors; GBool haveTextClip; // set if text has been drawn with a // clipping render mode GBool inType3Char; // inside a Type 3 CharProc GString *t3String; // Type 3 content string double t3WX, t3WY, // Type 3 character parameters t3LLX, t3LLY, t3URX, t3URY; GBool t3FillColorOnly; // operators should only use the fill color GBool t3Cacheable; // cleared if char is not cacheable GBool t3NeedsRestore; // set if a 'q' operator was issued #if OPI_SUPPORT int opi13Nest; // nesting level of OPI 1.3 objects int opi20Nest; // nesting level of OPI 2.0 objects #endif GBool ok; // set up ok? friend class WinPDFPrinter; }; #endif xpdf-3.03/xpdf/OptionalContent.cc0000644000076400007640000002746311622305345016317 0ustar dereknderekn//======================================================================== // // OptionalContent.cc // // Copyright 2008 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "GString.h" #include "GList.h" #include "Error.h" #include "Object.h" #include "PDFDoc.h" #include "PDFDocEncoding.h" #include "OptionalContent.h" //------------------------------------------------------------------------ #define ocPolicyAllOn 1 #define ocPolicyAnyOn 2 #define ocPolicyAnyOff 3 #define ocPolicyAllOff 4 //------------------------------------------------------------------------ // Max depth of nested visibility expressions. This is used to catch // infinite loops in the visibility expression object structure. #define visibilityExprRecursionLimit 50 // Max depth of nested display nodes. This is used to catch infinite // loops in the "Order" object structure. #define displayNodeRecursionLimit 50 //------------------------------------------------------------------------ OptionalContent::OptionalContent(PDFDoc *doc) { Object *ocProps; Object ocgList, defView, obj1, obj2; Ref ref1; OptionalContentGroup *ocg; int i; xref = doc->getXRef(); ocgs = new GList(); display = NULL; if ((ocProps = doc->getCatalog()->getOCProperties())->isDict()) { if (ocProps->dictLookup("OCGs", &ocgList)->isArray()) { //----- read the OCG list for (i = 0; i < ocgList.arrayGetLength(); ++i) { if (ocgList.arrayGetNF(i, &obj1)->isRef()) { ref1 = obj1.getRef(); obj1.fetch(xref, &obj2); if ((ocg = OptionalContentGroup::parse(&ref1, &obj2))) { ocgs->append(ocg); } obj2.free(); } obj1.free(); } //----- read the default viewing OCCD if (ocProps->dictLookup("D", &defView)->isDict()) { //----- initial state if (defView.dictLookup("OFF", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGetNF(i, &obj2)->isRef()) { ref1 = obj2.getRef(); if ((ocg = findOCG(&ref1))) { ocg->setState(gFalse); } else { error(errSyntaxError, -1, "Invalid OCG reference in OFF array in default viewing OCCD"); } } obj2.free(); } } obj1.free(); //----- display order if (defView.dictLookup("Order", &obj1)->isArray()) { display = OCDisplayNode::parse(&obj1, this, xref); } obj1.free(); } else { error(errSyntaxError, -1, "Missing or invalid default viewing OCCD"); } defView.free(); } ocgList.free(); } if (!display) { display = new OCDisplayNode(); } } OptionalContent::~OptionalContent() { deleteGList(ocgs, OptionalContentGroup); delete display; } int OptionalContent::getNumOCGs() { return ocgs->getLength(); } OptionalContentGroup *OptionalContent::getOCG(int idx) { return (OptionalContentGroup *)ocgs->get(idx); } OptionalContentGroup *OptionalContent::findOCG(Ref *ref) { OptionalContentGroup *ocg; int i; for (i = 0; i < ocgs->getLength(); ++i) { ocg = (OptionalContentGroup *)ocgs->get(i); if (ocg->matches(ref)) { return ocg; } } return NULL; } GBool OptionalContent::evalOCObject(Object *obj, GBool *visible) { OptionalContentGroup *ocg; int policy; Ref ref; Object obj2, obj3, obj4, obj5; int i; if (obj->isNull()) { return gFalse; } if (obj->isRef()) { ref = obj->getRef(); if ((ocg = findOCG(&ref))) { *visible = ocg->getState(); return gTrue; } } obj->fetch(xref, &obj2); if (obj2.isDict("OCMD")) { if (obj2.dictLookup("VE", &obj3)->isArray()) { *visible = evalOCVisibilityExpr(&obj3, 0); obj3.free(); } else { obj3.free(); policy = ocPolicyAnyOn; if (obj2.dictLookup("P", &obj3)->isName()) { if (obj3.isName("AllOn")) { policy = ocPolicyAllOn; } else if (obj3.isName("AnyOn")) { policy = ocPolicyAnyOn; } else if (obj3.isName("AnyOff")) { policy = ocPolicyAnyOff; } else if (obj3.isName("AllOff")) { policy = ocPolicyAllOff; } } obj3.free(); obj2.dictLookupNF("OCGs", &obj3); ocg = NULL; if (obj3.isRef()) { ref = obj3.getRef(); ocg = findOCG(&ref); } if (ocg) { *visible = (policy == ocPolicyAllOn || policy == ocPolicyAnyOn) ? ocg->getState() : !ocg->getState(); } else { *visible = gTrue; if (obj3.fetch(xref, &obj4)->isArray()) { for (i = 0; i < obj4.arrayGetLength(); ++i) { obj4.arrayGetNF(i, &obj5); if (obj5.isRef()) { ref = obj5.getRef(); if ((ocg = findOCG(&ref))) { switch (policy) { case ocPolicyAllOn: *visible = *visible && ocg->getState(); break; case ocPolicyAnyOn: *visible = *visible || ocg->getState(); break; case ocPolicyAnyOff: *visible = *visible || !ocg->getState(); break; case ocPolicyAllOff: *visible = *visible && !ocg->getState(); break; } } } obj5.free(); } } obj4.free(); } obj3.free(); } obj2.free(); return gTrue; } obj2.free(); return gFalse; } GBool OptionalContent::evalOCVisibilityExpr(Object *expr, int recursion) { OptionalContentGroup *ocg; Object expr2, op, obj; Ref ref; GBool ret; int i; if (recursion > visibilityExprRecursionLimit) { error(errSyntaxError, -1, "Loop detected in optional content visibility expression"); return gTrue; } if (expr->isRef()) { ref = expr->getRef(); if ((ocg = findOCG(&ref))) { return ocg->getState(); } } expr->fetch(xref, &expr2); if (!expr2.isArray() || expr2.arrayGetLength() < 1) { error(errSyntaxError, -1, "Invalid optional content visibility expression"); expr2.free(); return gTrue; } expr2.arrayGet(0, &op); if (op.isName("Not")) { if (expr2.arrayGetLength() == 2) { expr2.arrayGetNF(1, &obj); ret = !evalOCVisibilityExpr(&obj, recursion + 1); obj.free(); } else { error(errSyntaxError, -1, "Invalid optional content visibility expression"); ret = gTrue; } } else if (op.isName("And")) { ret = gTrue; for (i = 1; i < expr2.arrayGetLength() && ret; ++i) { expr2.arrayGetNF(i, &obj); ret = evalOCVisibilityExpr(&obj, recursion + 1); obj.free(); } } else if (op.isName("Or")) { ret = gFalse; for (i = 1; i < expr2.arrayGetLength() && !ret; ++i) { expr2.arrayGetNF(i, &obj); ret = evalOCVisibilityExpr(&obj, recursion + 1); obj.free(); } } else { error(errSyntaxError, -1, "Invalid optional content visibility expression"); ret = gTrue; } op.free(); expr2.free(); return ret; } //------------------------------------------------------------------------ OptionalContentGroup *OptionalContentGroup::parse(Ref *refA, Object *obj) { Unicode *nameA; int nameLenA; Object obj1, obj2, obj3; GString *s; OCUsageState viewStateA, printStateA; int i; if (!obj->isDict()) { return NULL; } if (!obj->dictLookup("Name", &obj1)->isString()) { error(errSyntaxError, -1, "Missing or invalid Name in OCG"); obj1.free(); return NULL; } s = obj1.getString(); if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { nameLenA = (s->getLength() - 2) / 2; nameA = (Unicode *)gmallocn(nameLenA, sizeof(Unicode)); for (i = 0; i < nameLenA; ++i) { nameA[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { nameLenA = s->getLength(); nameA = (Unicode *)gmallocn(nameLenA, sizeof(Unicode)); for (i = 0; i < nameLenA; ++i) { nameA[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } } obj1.free(); viewStateA = printStateA = ocUsageUnset; if (obj->dictLookup("Usage", &obj1)->isDict()) { if (obj1.dictLookup("View", &obj2)->isDict()) { if (obj2.dictLookup("ViewState", &obj3)->isName()) { if (obj3.isName("ON")) { viewStateA = ocUsageOn; } else { viewStateA = ocUsageOff; } } obj3.free(); } obj2.free(); if (obj1.dictLookup("Print", &obj2)->isDict()) { if (obj2.dictLookup("PrintState", &obj3)->isName()) { if (obj3.isName("ON")) { printStateA = ocUsageOn; } else { printStateA = ocUsageOff; } } obj3.free(); } obj2.free(); } obj1.free(); return new OptionalContentGroup(refA, nameA, nameLenA, viewStateA, printStateA); } OptionalContentGroup::OptionalContentGroup(Ref *refA, Unicode *nameA, int nameLenA, OCUsageState viewStateA, OCUsageState printStateA) { ref = *refA; name = nameA; nameLen = nameLenA; viewState = viewStateA; printState = printStateA; state = gTrue; } OptionalContentGroup::~OptionalContentGroup() { gfree(name); } GBool OptionalContentGroup::matches(Ref *refA) { return refA->num == ref.num && refA->gen == ref.gen; } //------------------------------------------------------------------------ OCDisplayNode *OCDisplayNode::parse(Object *obj, OptionalContent *oc, XRef *xref, int recursion) { Object obj2, obj3; Ref ref; OptionalContentGroup *ocgA; OCDisplayNode *node, *child; int i; if (recursion > displayNodeRecursionLimit) { error(errSyntaxError, -1, "Loop detected in optional content order"); return NULL; } if (obj->isRef()) { ref = obj->getRef(); if ((ocgA = oc->findOCG(&ref))) { return new OCDisplayNode(ocgA); } } obj->fetch(xref, &obj2); if (!obj2.isArray()) { obj2.free(); return NULL; } i = 0; if (obj2.arrayGetLength() >= 1) { if (obj2.arrayGet(0, &obj3)->isString()) { node = new OCDisplayNode(obj3.getString()); i = 1; } else { node = new OCDisplayNode(); } obj3.free(); } else { node = new OCDisplayNode(); } for (; i < obj2.arrayGetLength(); ++i) { obj2.arrayGetNF(i, &obj3); if ((child = OCDisplayNode::parse(&obj3, oc, xref, recursion + 1))) { if (!child->ocg && !child->name && node->getNumChildren() > 0) { node->getChild(node->getNumChildren() - 1)-> addChildren(child->takeChildren()); delete child; } else { node->addChild(child); } } obj3.free(); } obj2.free(); return node; } OCDisplayNode::OCDisplayNode() { name = NULL; nameLen = 0; ocg = NULL; children = NULL; } OCDisplayNode::OCDisplayNode(GString *nameA) { int i; if ((nameA->getChar(0) & 0xff) == 0xfe && (nameA->getChar(1) & 0xff) == 0xff) { nameLen = (nameA->getLength() - 2) / 2; name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); for (i = 0; i < nameLen; ++i) { name[i] = ((nameA->getChar(2 + 2*i) & 0xff) << 8) | (nameA->getChar(3 + 2*i) & 0xff); } } else { nameLen = nameA->getLength(); name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); for (i = 0; i < nameLen; ++i) { name[i] = pdfDocEncoding[nameA->getChar(i) & 0xff]; } } ocg = NULL; children = NULL; } OCDisplayNode::OCDisplayNode(OptionalContentGroup *ocgA) { nameLen = ocgA->getNameLength(); if (nameLen) { name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); memcpy(name, ocgA->getName(), nameLen * sizeof(Unicode)); } else { name = NULL; } ocg = ocgA; children = NULL; } void OCDisplayNode::addChild(OCDisplayNode *child) { if (!children) { children = new GList(); } children->append(child); } void OCDisplayNode::addChildren(GList *childrenA) { if (!children) { children = new GList(); } children->append(childrenA); delete childrenA; } GList *OCDisplayNode::takeChildren() { GList *childrenA; childrenA = children; children = NULL; return childrenA; } OCDisplayNode::~OCDisplayNode() { gfree(name); if (children) { deleteGList(children, OCDisplayNode); } } int OCDisplayNode::getNumChildren() { if (!children) { return 0; } return children->getLength(); } OCDisplayNode *OCDisplayNode::getChild(int idx) { return (OCDisplayNode *)children->get(idx); } xpdf-3.03/xpdf/XPDFApp.h0000644000076400007640000000561111622305345014232 0ustar dereknderekn//======================================================================== // // XPDFApp.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XPDFAPP_H #define XPDFAPP_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #define Object XtObject #include #undef Object #include "gtypes.h" #include "SplashTypes.h" class GString; class GList; class PDFDoc; class XPDFViewer; //------------------------------------------------------------------------ #define xpdfAppName "Xpdf" //------------------------------------------------------------------------ // XPDFApp //------------------------------------------------------------------------ class XPDFApp { public: XPDFApp(int *argc, char *argv[]); ~XPDFApp(); XPDFViewer *open(GString *fileName, int page = 1, GString *ownerPassword = NULL, GString *userPassword = NULL); XPDFViewer *openAtDest(GString *fileName, GString *dest, GString *ownerPassword = NULL, GString *userPassword = NULL); XPDFViewer *reopen(XPDFViewer *viewer, PDFDoc *doc, int page, GBool fullScreenA); void close(XPDFViewer *viewer, GBool closeLast); void quit(); void run(); //----- remote server void setRemoteName(char *remoteName); GBool remoteServerRunning(); void remoteExec(char *cmd); void remoteOpen(GString *fileName, int page, GBool raise); void remoteOpenAtDest(GString *fileName, GString *dest, GBool raise); void remoteReload(GBool raise); void remoteRaise(); void remoteQuit(); //----- resource/option values GString *getGeometry() { return geometry; } GString *getTitle() { return title; } GBool getInstallCmap() { return installCmap; } int getRGBCubeSize() { return rgbCubeSize; } GBool getReverseVideo() { return reverseVideo; } SplashColorPtr getPaperRGB() { return paperRGB; } Gulong getPaperPixel() { return paperPixel; } Gulong getMattePixel(GBool fullScreenA) { return fullScreenA ? fullScreenMattePixel : mattePixel; } GString *getInitialZoom() { return initialZoom; } void setFullScreen(GBool fullScreenA) { fullScreen = fullScreenA; } GBool getFullScreen() { return fullScreen; } XtAppContext getAppContext() { return appContext; } Widget getAppShell() { return appShell; } private: void getResources(); static void remoteMsgCbk(Widget widget, XtPointer ptr, XEvent *event, Boolean *cont); Display *display; int screenNum; XtAppContext appContext; Widget appShell; GList *viewers; // [XPDFViewer] Atom remoteAtom; Window remoteXWin; XPDFViewer *remoteViewer; Widget remoteWin; //----- resource/option values GString *geometry; GString *title; GBool installCmap; int rgbCubeSize; GBool reverseVideo; SplashColor paperRGB; Gulong paperPixel; Gulong mattePixel; Gulong fullScreenMattePixel; GString *initialZoom; GBool fullScreen; }; #endif xpdf-3.03/xpdf/find.xbm0000644000076400007640000000042011622305345014300 0ustar dereknderekn#define find_width 15 #define find_height 15 static unsigned char find_bits[] = { 0x38, 0x0e, 0x28, 0x0a, 0x2e, 0x3a, 0xfe, 0x3f, 0x7f, 0x7f, 0x61, 0x43, 0x61, 0x43, 0x61, 0x43, 0x61, 0x43, 0xe1, 0x43, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x21, 0x42, 0x3f, 0x7e}; xpdf-3.03/xpdf/about.xbm0000644000076400007640000000042311622305345014475 0ustar dereknderekn#define about_width 10 #define about_height 15 static unsigned char about_bits[] = { 0x78, 0x00, 0xfc, 0x00, 0xce, 0x01, 0x86, 0x01, 0x80, 0x01, 0x80, 0x01, 0xc0, 0x01, 0xe0, 0x00, 0x70, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x30, 0x00}; xpdf-3.03/xpdf/Dict.h0000644000076400007640000000335411622305345013715 0ustar dereknderekn//======================================================================== // // Dict.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef DICT_H #define DICT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" //------------------------------------------------------------------------ // Dict //------------------------------------------------------------------------ struct DictEntry { char *key; Object val; }; class Dict { public: // Constructor. Dict(XRef *xrefA); // Destructor. ~Dict(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get number of entries. int getLength() { return length; } // Add an entry. NB: does not copy key. void add(char *key, Object *val); // Check if dictionary is of specified type. GBool is(const char *type); // Look up an entry and return the value. Returns a null object // if is not in the dictionary. Object *lookup(const char *key, Object *obj, int recursion = 0); Object *lookupNF(const char *key, Object *obj); // Iterative accessors. char *getKey(int i); Object *getVal(int i, Object *obj); Object *getValNF(int i, Object *obj); // Set the xref pointer. This is only used in one special case: the // trailer dictionary, which is read before the xref table is // parsed. void setXRef(XRef *xrefA) { xref = xrefA; } private: XRef *xref; // the xref table for this PDF file DictEntry *entries; // array of entries int size; // size of array int length; // number of entries in dictionary int ref; // reference count DictEntry *find(const char *key); }; #endif xpdf-3.03/xpdf/Lexer.h0000644000076400007640000000364611622305345014115 0ustar dereknderekn//======================================================================== // // Lexer.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef LEXER_H #define LEXER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" #include "Stream.h" class XRef; #define tokBufSize 128 // size of token buffer //------------------------------------------------------------------------ // Lexer //------------------------------------------------------------------------ class Lexer { public: // Construct a lexer for a single stream. Deletes the stream when // lexer is deleted. Lexer(XRef *xref, Stream *str); // Construct a lexer for a stream or array of streams (assumes obj // is either a stream or array of streams). Lexer(XRef *xref, Object *obj); // Destructor. ~Lexer(); // Get the next object from the input stream. Object *getObj(Object *obj); // Skip to the beginning of the next line in the input stream. void skipToNextLine(); // Skip over one character. void skipChar() { getChar(); } // Get stream. Stream *getStream() { return curStr.isNone() ? (Stream *)NULL : curStr.getStream(); } // Get current position in file. This is only used for error // messages, so it returns an int instead of a Guint. int getPos() { return curStr.isNone() ? -1 : (int)curStr.streamGetPos(); } // Set position in file. void setPos(Guint pos, int dir = 0) { if (!curStr.isNone()) curStr.streamSetPos(pos, dir); } // Returns true if is a whitespace character. static GBool isSpace(int c); private: int getChar(); int lookChar(); Array *streams; // array of input streams int strPtr; // index of current stream Object curStr; // current stream GBool freeArray; // should lexer free the streams array? char tokBuf[tokBufSize]; // temporary token buffer }; #endif xpdf-3.03/xpdf/PDFCore.cc0000644000076400007640000015373211622305345014420 0ustar dereknderekn//======================================================================== // // PDFCore.cc // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "GString.h" #include "GList.h" #include "GlobalParams.h" #include "Splash.h" #include "SplashBitmap.h" #include "SplashPattern.h" #include "SplashPath.h" #include "Error.h" #include "ErrorCodes.h" #include "PDFDoc.h" #include "Link.h" #include "TextOutputDev.h" #include "CoreOutputDev.h" #include "PDFCore.h" //------------------------------------------------------------------------ // PDFCorePage //------------------------------------------------------------------------ PDFCorePage::PDFCorePage(int pageA, int wA, int hA, int tileWA, int tileHA) { page = pageA; tiles = new GList(); w = wA; h = hA; tileW = tileWA; tileH = tileHA; links = NULL; text = NULL; } PDFCorePage::~PDFCorePage() { deleteGList(tiles, PDFCoreTile); if (links) { delete links; } if (text) { delete text; } } //------------------------------------------------------------------------ // PDFCoreTile //------------------------------------------------------------------------ PDFCoreTile::PDFCoreTile(int xDestA, int yDestA) { xMin = 0; yMin = 0; xMax = 0; yMax = 0; xDest = xDestA; yDest = yDestA; bitmap = NULL; } PDFCoreTile::~PDFCoreTile() { if (bitmap) { delete bitmap; } } //------------------------------------------------------------------------ // PDFCore //------------------------------------------------------------------------ PDFCore::PDFCore(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool incrementalUpdate) { int i; doc = NULL; continuousMode = globalParams->getContinuousView(); drawAreaWidth = drawAreaHeight = 0; maxPageW = totalDocH = 0; pageY = NULL; topPage = 0; midPage = 0; scrollX = scrollY = 0; zoom = defZoom; dpi = 0; rotate = 0; selectPage = 0; selectULX = selectLRX = 0; selectULY = selectLRY = 0; dragging = gFalse; lastDragLeft = lastDragTop = gTrue; selectXorColor[0] = selectXorColor[1] = selectXorColor[2] = 0; splashColorXor(selectXorColor, paperColorA); historyCur = pdfHistorySize - 1; historyBLen = historyFLen = 0; for (i = 0; i < pdfHistorySize; ++i) { history[i].fileName = NULL; } pages = new GList(); curTile = NULL; splashColorCopy(paperColor, paperColorA); out = new CoreOutputDev(colorModeA, bitmapRowPadA, reverseVideoA, paperColorA, incrementalUpdate, &redrawCbk, this); out->startDoc(NULL); } PDFCore::~PDFCore() { int i; if (doc) { delete doc; } for (i = 0; i < pdfHistorySize; ++i) { if (history[i].fileName) { delete history[i].fileName; } } gfree(pageY); deleteGList(pages, PDFCorePage); delete out; } int PDFCore::loadFile(GString *fileName, GString *ownerPassword, GString *userPassword) { int err; setBusyCursor(gTrue); err = loadFile2(new PDFDoc(fileName->copy(), ownerPassword, userPassword, this)); setBusyCursor(gFalse); return err; } #ifdef WIN32 int PDFCore::loadFile(wchar_t *fileName, int fileNameLen, GString *ownerPassword, GString *userPassword) { int err; setBusyCursor(gTrue); err = loadFile2(new PDFDoc(fileName, fileNameLen, ownerPassword, userPassword, this)); setBusyCursor(gFalse); return err; } #endif int PDFCore::loadFile(BaseStream *stream, GString *ownerPassword, GString *userPassword) { int err; setBusyCursor(gTrue); err = loadFile2(new PDFDoc(stream, ownerPassword, userPassword, this)); setBusyCursor(gFalse); return err; } void PDFCore::loadDoc(PDFDoc *docA) { setBusyCursor(gTrue); loadFile2(docA); setBusyCursor(gFalse); } int PDFCore::loadFile2(PDFDoc *newDoc) { int err; double w, h, t; int i; // open the PDF file if (!newDoc->isOk()) { err = newDoc->getErrorCode(); delete newDoc; return err; } // replace old document if (doc) { delete doc; } doc = newDoc; if (out) { out->startDoc(doc->getXRef()); } // nothing displayed yet topPage = -99; midPage = -99; while (pages->getLength() > 0) { delete (PDFCorePage *)pages->del(0); } // compute the max unscaled page size maxUnscaledPageW = maxUnscaledPageH = 0; for (i = 1; i <= doc->getNumPages(); ++i) { w = doc->getPageCropWidth(i); h = doc->getPageCropHeight(i); if (doc->getPageRotate(i) == 90 || doc->getPageRotate(i) == 270) { t = w; w = h; h = t; } if (w > maxUnscaledPageW) { maxUnscaledPageW = w; } if (h > maxUnscaledPageH) { maxUnscaledPageH = h; } } return errNone; } void PDFCore::clear() { if (!doc) { return; } // no document delete doc; doc = NULL; out->clear(); // no page displayed topPage = -99; midPage = -99; while (pages->getLength() > 0) { delete (PDFCorePage *)pages->del(0); } // redraw scrollX = scrollY = 0; redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, gTrue); updateScrollbars(); } PDFDoc *PDFCore::takeDoc(GBool redraw) { PDFDoc *docA; if (!doc) { return NULL; } // no document docA = doc; doc = NULL; out->clear(); // no page displayed topPage = -99; midPage = -99; while (pages->getLength() > 0) { delete (PDFCorePage *)pages->del(0); } // redraw scrollX = scrollY = 0; if (redraw) { redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, gTrue); updateScrollbars(); } return docA; } void PDFCore::displayPage(int topPageA, double zoomA, int rotateA, GBool scrollToTop, GBool addToHist) { int scrollXA, scrollYA; scrollXA = scrollX; if (continuousMode) { scrollYA = -1; } else if (scrollToTop) { scrollYA = 0; } else { scrollYA = scrollY; } if (zoomA != zoom) { scrollXA = 0; scrollYA = continuousMode ? -1 : 0; } dragging = gFalse; lastDragLeft = lastDragTop = gTrue; update(topPageA, scrollXA, scrollYA, zoomA, rotateA, gTrue, addToHist, gTrue); } void PDFCore::displayDest(LinkDest *dest, double zoomA, int rotateA, GBool addToHist) { Ref pageRef; int topPageA; int dx, dy, scrollXA, scrollYA; if (dest->isPageRef()) { pageRef = dest->getPageRef(); topPageA = doc->findPage(pageRef.num, pageRef.gen); } else { topPageA = dest->getPageNum(); } if (topPageA <= 0 || topPageA > doc->getNumPages()) { topPageA = 1; } scrollXA = scrollX; scrollYA = continuousMode ? -1 : scrollY; switch (dest->getKind()) { case destXYZ: cvtUserToDev(topPageA, dest->getLeft(), dest->getTop(), &dx, &dy); scrollXA = dest->getChangeLeft() ? dx : scrollX; if (continuousMode) { if (topPage <= 0) { scrollYA = -1; } else if (dest->getChangeTop()) { scrollYA = pageY[topPageA - 1] + dy; } else { scrollYA = pageY[topPageA - 1] + (scrollY - pageY[topPage - 1]); } } else { if (dest->getChangeTop()) { scrollYA = dy; } else if (topPage > 0) { scrollYA = scrollY; } else { scrollYA = 0; } } //~ this doesn't currently handle the zoom parameter update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse, addToHist && topPageA != topPage, gTrue); break; case destFit: case destFitB: scrollXA = 0; scrollYA = continuousMode ? -1 : 0; update(topPageA, scrollXA, scrollYA, zoomPage, rotate, gFalse, addToHist && topPageA != topPage, gTrue); break; case destFitH: case destFitBH: //~ do fit: need a function similar to zoomToRect which will //~ accept an absolute top coordinate (rather than centering) scrollXA = 0; cvtUserToDev(topPageA, 0, dest->getTop(), &dx, &dy); if (continuousMode) { if (topPage <= 0) { scrollYA = -1; } else if (dest->getChangeTop()) { scrollYA = pageY[topPageA - 1] + dy; } else { scrollYA = pageY[topPageA - 1] + (scrollY - pageY[topPage - 1]); } } else { if (dest->getChangeTop()) { scrollYA = dy; } else if (topPage > 0) { scrollYA = scrollY; } else { scrollYA = 0; } } update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse, addToHist && topPageA != topPage, gTrue); break; case destFitV: case destFitBV: //~ do fit: need a function similar to zoomToRect which will //~ accept an absolute left coordinate (rather than centering) if (dest->getChangeLeft()) { cvtUserToDev(topPageA, dest->getLeft(), 0, &dx, &dy); scrollXA = dx; } else { scrollXA = scrollX; } scrollYA = continuousMode ? -1 : 0; update(topPageA, scrollXA, scrollYA, zoom, rotate, gFalse, addToHist && topPageA != topPage, gTrue); break; case destFitR: zoomToRect(topPageA, dest->getLeft(), dest->getTop(), dest->getRight(), dest->getBottom()); break; } } void PDFCore::update(int topPageA, int scrollXA, int scrollYA, double zoomA, int rotateA, GBool force, GBool addToHist, GBool adjustScrollX) { double hDPI, vDPI, dpiA, uw, uh, ut; int w, h, t, x0, x1, y0, y1, x, y; int rot; int pg0, pg1; PDFCoreTile *tile; PDFCorePage *page; PDFHistory *hist; GBool needUpdate; int i, j; // check for document and valid page number if (!doc) { // save the new settings zoom = zoomA; rotate = rotateA; return; } if (topPageA <= 0 || topPageA > doc->getNumPages()) { return; } needUpdate = gFalse; // check for changes to the PDF file if ((force || (!continuousMode && topPage != topPageA)) && checkForNewFile()) { if (loadFile(doc->getFileName()) == errNone) { if (topPageA > doc->getNumPages()) { topPageA = doc->getNumPages(); } needUpdate = gTrue; } } // compute the DPI if (continuousMode) { uw = maxUnscaledPageW; uh = maxUnscaledPageH; rot = rotateA; } else { uw = doc->getPageCropWidth(topPageA); uh = doc->getPageCropHeight(topPageA); rot = rotateA + doc->getPageRotate(topPageA); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } } if (rot == 90 || rot == 270) { ut = uw; uw = uh; uh = ut; } if (zoomA == zoomPage) { hDPI = (drawAreaWidth / uw) * 72; if (continuousMode) { vDPI = ((drawAreaHeight - continuousModePageSpacing) / uh) * 72; } else { vDPI = (drawAreaHeight / uh) * 72; } dpiA = (hDPI < vDPI) ? hDPI : vDPI; } else if (zoomA == zoomWidth) { dpiA = (drawAreaWidth / uw) * 72; } else { dpiA = 0.01 * zoomA * 72; } // this can happen if the window hasn't been sized yet if (dpiA <= 0) { dpiA = 1; } // if the display properties have changed, create a new PDFCorePage // object if (force || pages->getLength() == 0 || (!continuousMode && topPageA != topPage) || fabs(zoomA - zoom) > 1e-8 || fabs(dpiA - dpi) > 1e-8 || rotateA != rotate) { needUpdate = gTrue; setSelection(0, 0, 0, 0, 0); while (pages->getLength() > 0) { delete (PDFCorePage *)pages->del(0); } zoom = zoomA; rotate = rotateA; dpi = dpiA; if (continuousMode) { maxPageW = totalDocH = 0; pageY = (int *)greallocn(pageY, doc->getNumPages(), sizeof(int)); for (i = 1; i <= doc->getNumPages(); ++i) { pageY[i-1] = totalDocH; w = (int)((doc->getPageCropWidth(i) * dpi) / 72 + 0.5); h = (int)((doc->getPageCropHeight(i) * dpi) / 72 + 0.5); rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { t = w; w = h; h = t; } if (w > maxPageW) { maxPageW = w; } totalDocH += h; if (i < doc->getNumPages()) { totalDocH += continuousModePageSpacing; } } } else { rot = rotate + doc->getPageRotate(topPageA); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } addPage(topPageA, rot); } } else { // erase the selection if (selectULX != selectLRX && selectULY != selectLRY) { xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY, new SplashSolidColor(selectXorColor)); } } if (continuousMode) { page = NULL; // make gcc happy } else { page = (PDFCorePage *)pages->get(0); } topPage = topPageA; midPage = topPage; // adjust the scroll position scrollX = scrollXA; if (continuousMode && scrollYA < 0) { scrollY = pageY[topPage - 1]; } else { scrollY = scrollYA; } if (continuousMode && adjustScrollX) { rot = rotate + doc->getPageRotate(topPage); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { w = (int)((doc->getPageCropHeight(topPage) * dpi) / 72 + 0.5); } else { w = (int)((doc->getPageCropWidth(topPage) * dpi) / 72 + 0.5); } if (scrollX < (maxPageW - w) / 2) { scrollX = (maxPageW - w) / 2; } } w = continuousMode ? maxPageW : page->w; if (scrollX > w - drawAreaWidth) { scrollX = w - drawAreaWidth; } if (scrollX < 0) { scrollX = 0; } h = continuousMode ? totalDocH : page->h; if (scrollY > h - drawAreaHeight) { scrollY = h - drawAreaHeight; } if (scrollY < 0) { scrollY = 0; } // find topPage, and the first and last pages to be rasterized if (continuousMode) { //~ should use a binary search for (i = 2; i <= doc->getNumPages(); ++i) { if (pageY[i-1] > scrollY - drawAreaHeight / 2) { break; } } pg0 = i - 1; for (i = pg0 + 1; i <= doc->getNumPages(); ++i) { if (pageY[i-1] > scrollY) { break; } } topPage = i - 1; for (i = topPage + 1; i <= doc->getNumPages(); ++i) { if (pageY[i-1] > scrollY + drawAreaHeight / 2) { break; } } midPage = i - 1; for (i = midPage + 1; i <= doc->getNumPages(); ++i) { if (pageY[i-1] > scrollY + drawAreaHeight + drawAreaHeight / 2) { break; } } pg1 = i - 1; // delete pages that are no longer needed and insert new pages // objects that are needed while (pages->getLength() > 0 && ((PDFCorePage *)pages->get(0))->page < pg0) { delete (PDFCorePage *)pages->del(0); } i = pages->getLength() - 1; while (i > 0 && ((PDFCorePage *)pages->get(i))->page > pg1) { delete (PDFCorePage *)pages->del(i--); } j = pages->getLength() > 0 ? ((PDFCorePage *)pages->get(0))->page - 1 : pg1; for (i = pg0; i <= j; ++i) { rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } addPage(i, rot); } j = ((PDFCorePage *)pages->get(pages->getLength() - 1))->page; for (i = j + 1; i <= pg1; ++i) { rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } addPage(i, rot); } } else { pg0 = pg1 = topPage; } // delete tiles that are no longer needed for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); j = 0; while (j < page->tiles->getLength()) { tile = (PDFCoreTile *)page->tiles->get(j); if (continuousMode) { y0 = pageY[page->page - 1] + tile->yMin; y1 = pageY[page->page - 1] + tile->yMax; } else { y0 = tile->yMin; y1 = tile->yMax; } if (tile->xMax < scrollX - drawAreaWidth / 2 || tile->xMin > scrollX + drawAreaWidth + drawAreaWidth / 2 || y1 < scrollY - drawAreaHeight / 2 || y0 > scrollY + drawAreaHeight + drawAreaHeight / 2) { delete (PDFCoreTile *)page->tiles->del(j); } else { ++j; } } } // update page positions for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); page->xDest = -scrollX; if (continuousMode) { page->yDest = pageY[page->page - 1] - scrollY; } else { page->yDest = -scrollY; } if (continuousMode) { if (page->w < maxPageW) { page->xDest += (maxPageW - page->w) / 2; } if (maxPageW < drawAreaWidth) { page->xDest += (drawAreaWidth - maxPageW) / 2; } } else if (page->w < drawAreaWidth) { page->xDest += (drawAreaWidth - page->w) / 2; } if (continuousMode && totalDocH < drawAreaHeight) { page->yDest += (drawAreaHeight - totalDocH) / 2; } else if (!continuousMode && page->h < drawAreaHeight) { page->yDest += (drawAreaHeight - page->h) / 2; } } // rasterize any new tiles for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); x0 = page->xDest; x1 = x0 + page->w - 1; if (x0 < -drawAreaWidth / 2) { x0 = -drawAreaWidth / 2; } if (x1 > drawAreaWidth + drawAreaWidth / 2) { x1 = drawAreaWidth + drawAreaWidth / 2; } x0 = ((x0 - page->xDest) / page->tileW) * page->tileW; x1 = ((x1 - page->xDest) / page->tileW) * page->tileW; y0 = page->yDest; y1 = y0 + page->h - 1; if (y0 < -drawAreaHeight / 2) { y0 = -drawAreaHeight / 2; } if (y1 > drawAreaHeight + drawAreaHeight / 2) { y1 = drawAreaHeight + drawAreaHeight / 2; } y0 = ((y0 - page->yDest) / page->tileH) * page->tileH; y1 = ((y1 - page->yDest) / page->tileH) * page->tileH; for (y = y0; y <= y1; y += page->tileH) { for (x = x0; x <= x1; x += page->tileW) { needTile(page, x, y); } } } // update tile positions for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); for (j = 0; j < page->tiles->getLength(); ++j) { tile = (PDFCoreTile *)page->tiles->get(j); tile->xDest = tile->xMin - scrollX; if (continuousMode) { tile->yDest = tile->yMin + pageY[page->page - 1] - scrollY; } else { tile->yDest = tile->yMin - scrollY; } if (continuousMode) { if (page->w < maxPageW) { tile->xDest += (maxPageW - page->w) / 2; } if (maxPageW < drawAreaWidth) { tile->xDest += (drawAreaWidth - maxPageW) / 2; } } else if (page->w < drawAreaWidth) { tile->xDest += (drawAreaWidth - page->w) / 2; } if (continuousMode && totalDocH < drawAreaHeight) { tile->yDest += (drawAreaHeight - totalDocH) / 2; } else if (!continuousMode && page->h < drawAreaHeight) { tile->yDest += (drawAreaHeight - page->h) / 2; } } } // redraw the selection if (selectULX != selectLRX && selectULY != selectLRY) { xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY, new SplashSolidColor(selectXorColor)); } // redraw the window redrawWindow(0, 0, drawAreaWidth, drawAreaHeight, needUpdate); updateScrollbars(); // add to history if (addToHist) { if (++historyCur == pdfHistorySize) { historyCur = 0; } hist = &history[historyCur]; if (hist->fileName) { delete hist->fileName; } if (doc->getFileName()) { hist->fileName = doc->getFileName()->copy(); } else { hist->fileName = NULL; } hist->page = topPage; if (historyBLen < pdfHistorySize) { ++historyBLen; } historyFLen = 0; } } void PDFCore::addPage(int pg, int rot) { PDFCorePage *page; int w, h, t, tileW, tileH, i; w = (int)((doc->getPageCropWidth(pg) * dpi) / 72 + 0.5); h = (int)((doc->getPageCropHeight(pg) * dpi) / 72 + 0.5); if (rot == 90 || rot == 270) { t = w; w = h; h = t; } tileW = 2 * drawAreaWidth; if (tileW < 1500) { tileW = 1500; } if (tileW > w) { // tileW can't be zero -- we end up with div-by-zero problems tileW = w ? w : 1; } tileH = 2 * drawAreaHeight; if (tileH < 1500) { tileH = 1500; } if (tileH > h) { // tileH can't be zero -- we end up with div-by-zero problems tileH = h ? h : 1; } page = new PDFCorePage(pg, w, h, tileW, tileH); for (i = 0; i < pages->getLength() && pg > ((PDFCorePage *)pages->get(i))->page; ++i) ; pages->insert(i, page); } void PDFCore::needTile(PDFCorePage *page, int x, int y) { PDFCoreTile *tile; TextOutputDev *textOut; int xDest, yDest, sliceW, sliceH; int i; for (i = 0; i < page->tiles->getLength(); ++i) { tile = (PDFCoreTile *)page->tiles->get(i); if (x == tile->xMin && y == tile->yMin) { return; } } setBusyCursor(gTrue); sliceW = page->tileW; if (x + sliceW > page->w) { sliceW = page->w - x; } sliceH = page->tileH; if (y + sliceH > page->h) { sliceH = page->h - y; } xDest = x - scrollX; if (continuousMode) { yDest = y + pageY[page->page - 1] - scrollY; } else { yDest = y - scrollY; } if (continuousMode) { if (page->w < maxPageW) { xDest += (maxPageW - page->w) / 2; } if (maxPageW < drawAreaWidth) { xDest += (drawAreaWidth - maxPageW) / 2; } } else if (page->w < drawAreaWidth) { xDest += (drawAreaWidth - page->w) / 2; } if (continuousMode && totalDocH < drawAreaHeight) { yDest += (drawAreaHeight - totalDocH) / 2; } else if (!continuousMode && page->h < drawAreaHeight) { yDest += (drawAreaHeight - page->h) / 2; } curTile = tile = newTile(xDest, yDest); curPage = page; tile->xMin = x; tile->yMin = y; tile->xMax = x + sliceW; tile->yMax = y + sliceH; tile->edges = 0; if (tile->xMin == 0) { tile->edges |= pdfCoreTileLeftEdge; } if (tile->xMax == page->w) { tile->edges |= pdfCoreTileRightEdge; } if (continuousMode) { if (tile->yMin == 0) { tile->edges |= pdfCoreTileTopSpace; if (page->page == 1) { tile->edges |= pdfCoreTileTopEdge; } } if (tile->yMax == page->h) { tile->edges |= pdfCoreTileBottomSpace; if (page->page == doc->getNumPages()) { tile->edges |= pdfCoreTileBottomEdge; } } } else { if (tile->yMin == 0) { tile->edges |= pdfCoreTileTopEdge; } if (tile->yMax == page->h) { tile->edges |= pdfCoreTileBottomEdge; } } doc->displayPageSlice(out, page->page, dpi, dpi, rotate, gFalse, gTrue, gFalse, x, y, sliceW, sliceH); tile->bitmap = out->takeBitmap(); memcpy(tile->ctm, out->getDefCTM(), 6 * sizeof(double)); memcpy(tile->ictm, out->getDefICTM(), 6 * sizeof(double)); if (!page->links) { page->links = doc->getLinks(page->page); } if (!page->text) { if ((textOut = new TextOutputDev(NULL, gTrue, 0, gFalse, gFalse))) { doc->displayPage(textOut, page->page, dpi, dpi, rotate, gFalse, gTrue, gFalse); page->text = textOut->takeText(); delete textOut; } } page->tiles->append(tile); curTile = NULL; curPage = NULL; setBusyCursor(gFalse); } GBool PDFCore::gotoNextPage(int inc, GBool top) { int pg, scrollYA; if (!doc || doc->getNumPages() == 0 || topPage >= doc->getNumPages()) { return gFalse; } if ((pg = topPage + inc) > doc->getNumPages()) { pg = doc->getNumPages(); } if (continuousMode) { scrollYA = -1; } else if (top) { scrollYA = 0; } else { scrollYA = scrollY; } update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue, gTrue); return gTrue; } GBool PDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) { int pg, scrollYA; if (!doc || doc->getNumPages() == 0 || topPage <= 1) { return gFalse; } if ((pg = topPage - dec) < 1) { pg = 1; } if (continuousMode) { scrollYA = -1; } else if (top) { scrollYA = 0; } else if (bottom) { scrollYA = ((PDFCorePage *)pages->get(0))->h - drawAreaHeight; if (scrollYA < 0) { scrollYA = 0; } } else { scrollYA = scrollY; } update(pg, scrollX, scrollYA, zoom, rotate, gFalse, gTrue, gTrue); return gTrue; } GBool PDFCore::gotoNamedDestination(GString *dest) { LinkDest *d; if (!doc) { return gFalse; } if (!(d = doc->findDest(dest))) { return gFalse; } displayDest(d, zoom, rotate, gTrue); delete d; return gTrue; } GBool PDFCore::goForward() { int pg; if (historyFLen == 0) { return gFalse; } if (++historyCur == pdfHistorySize) { historyCur = 0; } --historyFLen; ++historyBLen; if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) { if (loadFile(history[historyCur].fileName) != errNone) { return gFalse; } } pg = history[historyCur].page; update(pg, scrollX, continuousMode ? -1 : scrollY, zoom, rotate, gFalse, gFalse, gTrue); return gTrue; } GBool PDFCore::goBackward() { int pg; if (historyBLen <= 1) { return gFalse; } if (--historyCur < 0) { historyCur = pdfHistorySize - 1; } --historyBLen; ++historyFLen; if (!doc || history[historyCur].fileName->cmp(doc->getFileName()) != 0) { if (loadFile(history[historyCur].fileName) != errNone) { return gFalse; } } pg = history[historyCur].page; update(pg, scrollX, continuousMode ? -1 : scrollY, zoom, rotate, gFalse, gFalse, gTrue); return gTrue; } void PDFCore::scrollLeft(int nCols) { scrollTo(scrollX - nCols, scrollY); } void PDFCore::scrollRight(int nCols) { scrollTo(scrollX + nCols, scrollY); } void PDFCore::scrollUp(int nLines) { scrollTo(scrollX, scrollY - nLines); } void PDFCore::scrollUpPrevPage(int nLines) { if (!continuousMode && scrollY == 0) { gotoPrevPage(1, gFalse, gTrue); } else { scrollTo(scrollX, scrollY - nLines); } } void PDFCore::scrollDown(int nLines) { scrollTo(scrollX, scrollY + nLines); } void PDFCore::scrollDownNextPage(int nLines) { if (!continuousMode && scrollY >= ((PDFCorePage *)pages->get(0))->h - drawAreaHeight) { gotoNextPage(1, gTrue); } else { scrollTo(scrollX, scrollY + nLines); } } void PDFCore::scrollPageUp() { if (!continuousMode && scrollY == 0) { gotoPrevPage(1, gFalse, gTrue); } else { scrollTo(scrollX, scrollY - drawAreaHeight); } } void PDFCore::scrollPageDown() { if (!continuousMode && pages->getLength() > 0 && scrollY >= ((PDFCorePage *)pages->get(0))->h - drawAreaHeight) { gotoNextPage(1, gTrue); } else { scrollTo(scrollX, scrollY + drawAreaHeight); } } void PDFCore::scrollTo(int x, int y) { update(topPage, x, y < 0 ? 0 : y, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToLeftEdge() { update(topPage, 0, scrollY, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToRightEdge() { PDFCorePage *page; page = (PDFCorePage *)pages->get(0); update(topPage, page->w - drawAreaWidth, scrollY, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToTopEdge() { int y; y = continuousMode ? pageY[topPage - 1] : 0; update(topPage, scrollX, y, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToBottomEdge() { PDFCorePage *page; int y, i; for (i = pages->getLength() - 1; i > 0; --i) { page = (PDFCorePage *)pages->get(i); if (page->yDest < drawAreaHeight) { break; } } page = (PDFCorePage *)pages->get(i); if (continuousMode) { y = pageY[page->page - 1] + page->h - drawAreaHeight; } else { y = page->h - drawAreaHeight; } update(topPage, scrollX, y, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToTopLeft() { int y; y = continuousMode ? pageY[topPage - 1] : 0; update(topPage, 0, y, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::scrollToBottomRight() { PDFCorePage *page; int x, y, i; for (i = pages->getLength() - 1; i > 0; --i) { page = (PDFCorePage *)pages->get(i); if (page->yDest < drawAreaHeight) { break; } } page = (PDFCorePage *)pages->get(i); x = page->w - drawAreaWidth; if (continuousMode) { y = pageY[page->page - 1] + page->h - drawAreaHeight; } else { y = page->h - drawAreaHeight; } update(topPage, x, y, zoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::zoomToRect(int pg, double ulx, double uly, double lrx, double lry) { int x0, y0, x1, y1, u, sx, sy; double rx, ry, newZoom, t; PDFCorePage *p; cvtUserToDev(pg, ulx, uly, &x0, &y0); cvtUserToDev(pg, lrx, lry, &x1, &y1); if (x0 > x1) { u = x0; x0 = x1; x1 = u; } if (y0 > y1) { u = y0; y0 = y1; y1 = u; } rx = (double)drawAreaWidth / (double)(x1 - x0); ry = (double)drawAreaHeight / (double)(y1 - y0); if (rx < ry) { newZoom = rx * (dpi / (0.01 * 72)); sx = (int)(rx * x0); t = (drawAreaHeight * (x1 - x0)) / drawAreaWidth; sy = (int)(rx * (y0 + y1 - t) / 2); if (continuousMode) { if ((p = findPage(pg)) && p->w < maxPageW) { sx += (int)(0.5 * rx * (maxPageW - p->w)); } u = (pg - 1) * continuousModePageSpacing; sy += (int)(rx * (pageY[pg - 1] - u)) + u; } } else { newZoom = ry * (dpi / (0.01 * 72)); t = (drawAreaWidth * (y1 - y0)) / drawAreaHeight; sx = (int)(ry * (x0 + x1 - t) / 2); sy = (int)(ry * y0); if (continuousMode) { if ((p = findPage(pg)) && p->w < maxPageW) { sx += (int)(0.5 * rx * (maxPageW - p->w)); } u = (pg - 1) * continuousModePageSpacing; sy += (int)(ry * (pageY[pg - 1] - u)) + u; } } update(pg, sx, sy, newZoom, rotate, gFalse, gFalse, gFalse); } void PDFCore::zoomCentered(double zoomA) { int sx, sy, rot, hAdjust, vAdjust, i; double dpi1, dpi2, pageW, pageH; PDFCorePage *page; if (zoomA == zoomPage) { if (continuousMode) { pageW = (rotate == 90 || rotate == 270) ? maxUnscaledPageH : maxUnscaledPageW; pageH = (rotate == 90 || rotate == 270) ? maxUnscaledPageW : maxUnscaledPageH; dpi1 = 72.0 * (double)drawAreaWidth / pageW; dpi2 = 72.0 * (double)(drawAreaHeight - continuousModePageSpacing) / pageH; if (dpi2 < dpi1) { dpi1 = dpi2; } } else { // in single-page mode, sx=sy=0 -- so dpi1 is irrelevant dpi1 = dpi; } sx = 0; } else if (zoomA == zoomWidth) { if (continuousMode) { pageW = (rotate == 90 || rotate == 270) ? maxUnscaledPageH : maxUnscaledPageW; } else { rot = rotate + doc->getPageRotate(topPage); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } pageW = (rot == 90 || rot == 270) ? doc->getPageCropHeight(topPage) : doc->getPageCropWidth(topPage); } dpi1 = 72.0 * (double)drawAreaWidth / pageW; sx = 0; } else if (zoomA <= 0) { return; } else { dpi1 = 72.0 * zoomA / 100.0; if ((page = (PDFCorePage *)pages->get(0)) && page->xDest > 0) { hAdjust = page->xDest; } else { hAdjust = 0; } sx = (int)((scrollX - hAdjust + drawAreaWidth / 2) * (dpi1 / dpi)) - drawAreaWidth / 2; if (sx < 0) { sx = 0; } } if (continuousMode) { // we can't just multiply scrollY by dpi1/dpi -- the rounding // errors add up (because the pageY values are integers) -- so // we compute the pageY values at the new zoom level instead sy = 0; for (i = 1; i < topPage; ++i) { rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { sy += (int)((doc->getPageCropWidth(i) * dpi1) / 72 + 0.5); } else { sy += (int)((doc->getPageCropHeight(i) * dpi1) / 72 + 0.5); } } vAdjust = (topPage - 1) * continuousModePageSpacing; sy = sy + (int)((scrollY - pageY[topPage - 1] + drawAreaHeight / 2) * (dpi1 / dpi)) + vAdjust - drawAreaHeight / 2; } else { sy = (int)((scrollY + drawAreaHeight / 2) * (dpi1 / dpi)) - drawAreaHeight / 2; } update(topPage, sx, sy, zoomA, rotate, gFalse, gFalse, gFalse); } // Zoom so that the current page(s) fill the window width. Maintain // the vertical center. void PDFCore::zoomToCurrentWidth() { double w, maxW, dpi1; int sx, sy, vAdjust, rot, i; // compute the maximum page width of visible pages rot = rotate + doc->getPageRotate(topPage); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { maxW = doc->getPageCropHeight(topPage); } else { maxW = doc->getPageCropWidth(topPage); } if (continuousMode) { for (i = topPage + 1; i < doc->getNumPages() && pageY[i-1] < scrollY + drawAreaHeight; ++i) { rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { w = doc->getPageCropHeight(i); } else { w = doc->getPageCropWidth(i); } if (w > maxW) { maxW = w; } } } // compute the resolution dpi1 = (drawAreaWidth / maxW) * 72; // compute the horizontal scroll position if (continuousMode) { sx = ((int)(maxPageW * dpi1 / dpi) - drawAreaWidth) / 2; } else { sx = 0; } // compute the vertical scroll position if (continuousMode) { // we can't just multiply scrollY by dpi1/dpi -- the rounding // errors add up (because the pageY values are integers) -- so // we compute the pageY values at the new zoom level instead sy = 0; for (i = 1; i < topPage; ++i) { rot = rotate + doc->getPageRotate(i); if (rot >= 360) { rot -= 360; } else if (rot < 0) { rot += 360; } if (rot == 90 || rot == 270) { sy += (int)((doc->getPageCropWidth(i) * dpi1) / 72 + 0.5); } else { sy += (int)((doc->getPageCropHeight(i) * dpi1) / 72 + 0.5); } } vAdjust = (topPage - 1) * continuousModePageSpacing; sy = sy + (int)((scrollY - pageY[topPage - 1] + drawAreaHeight / 2) * (dpi1 / dpi)) + vAdjust - drawAreaHeight / 2; } else { sy = (int)((scrollY + drawAreaHeight / 2) * (dpi1 / dpi)) - drawAreaHeight / 2; } update(topPage, sx, sy, (dpi1 * 100) / 72, rotate, gFalse, gFalse, gFalse); } void PDFCore::setContinuousMode(GBool cm) { if (continuousMode != cm) { continuousMode = cm; update(topPage, scrollX, -1, zoom, rotate, gTrue, gFalse, gTrue); } } void PDFCore::setSelectionColor(SplashColor color) { splashColorCopy(selectXorColor, color); splashColorXor(selectXorColor, paperColor); } void PDFCore::setSelection(int newSelectPage, int newSelectULX, int newSelectULY, int newSelectLRX, int newSelectLRY) { int x0, y0, x1, y1, py; GBool haveSel, newHaveSel; GBool needRedraw, needScroll; GBool moveLeft, moveRight, moveTop, moveBottom; PDFCorePage *page; haveSel = selectULX != selectLRX && selectULY != selectLRY; newHaveSel = newSelectULX != newSelectLRX && newSelectULY != newSelectLRY; // erase old selection on off-screen bitmap needRedraw = gFalse; if (haveSel) { xorRectangle(selectPage, selectULX, selectULY, selectLRX, selectLRY, new SplashSolidColor(selectXorColor)); needRedraw = gTrue; } // draw new selection on off-screen bitmap if (newHaveSel) { xorRectangle(newSelectPage, newSelectULX, newSelectULY, newSelectLRX, newSelectLRY, new SplashSolidColor(selectXorColor)); needRedraw = gTrue; } // check which edges moved if (!haveSel || newSelectPage != selectPage) { moveLeft = moveTop = moveRight = moveBottom = gTrue; } else { moveLeft = newSelectULX != selectULX; moveTop = newSelectULY != selectULY; moveRight = newSelectLRX != selectLRX; moveBottom = newSelectLRY != selectLRY; } // redraw currently visible part of bitmap if (needRedraw) { if (!haveSel) { page = findPage(newSelectPage); x0 = newSelectULX; y0 = newSelectULY; x1 = newSelectLRX; y1 = newSelectLRY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } else if (!newHaveSel) { if ((page = findPage(selectPage))) { x0 = selectULX; y0 = selectULY; x1 = selectLRX; y1 = selectLRY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } } else { page = findPage(newSelectPage); if (moveLeft) { x0 = newSelectULX < selectULX ? newSelectULX : selectULX; y0 = newSelectULY < selectULY ? newSelectULY : selectULY; x1 = newSelectULX > selectULX ? newSelectULX : selectULX; y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } if (moveRight) { x0 = newSelectLRX < selectLRX ? newSelectLRX : selectLRX; y0 = newSelectULY < selectULY ? newSelectULY : selectULY; x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX; y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } if (moveTop) { x0 = newSelectULX < selectULX ? newSelectULX : selectULX; y0 = newSelectULY < selectULY ? newSelectULY : selectULY; x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX; y1 = newSelectULY > selectULY ? newSelectULY : selectULY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } if (moveBottom) { x0 = newSelectULX < selectULX ? newSelectULX : selectULX; y0 = newSelectLRY < selectLRY ? newSelectLRY : selectLRY; x1 = newSelectLRX > selectLRX ? newSelectLRX : selectLRX; y1 = newSelectLRY > selectLRY ? newSelectLRY : selectLRY; redrawWindow(page->xDest + x0, page->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, gFalse); } } } // switch to new selection coords selectPage = newSelectPage; selectULX = newSelectULX; selectULY = newSelectULY; selectLRX = newSelectLRX; selectLRY = newSelectLRY; // scroll if necessary if (newHaveSel) { page = findPage(selectPage); needScroll = gFalse; x0 = scrollX; y0 = scrollY; if (moveLeft && page->xDest + selectULX < 0) { x0 += page->xDest + selectULX; needScroll = gTrue; } else if (moveRight && page->xDest + selectLRX >= drawAreaWidth) { x0 += page->xDest + selectLRX - drawAreaWidth; needScroll = gTrue; } else if (moveLeft && page->xDest + selectULX >= drawAreaWidth) { x0 += page->xDest + selectULX - drawAreaWidth; needScroll = gTrue; } else if (moveRight && page->xDest + selectLRX < 0) { x0 += page->xDest + selectLRX; needScroll = gTrue; } py = continuousMode ? pageY[selectPage - 1] : 0; if (moveTop && py + selectULY < y0) { y0 = py + selectULY; needScroll = gTrue; } else if (moveBottom && py + selectLRY >= y0 + drawAreaHeight) { y0 = py + selectLRY - drawAreaHeight; needScroll = gTrue; } else if (moveTop && py + selectULY >= y0 + drawAreaHeight) { y0 = py + selectULY - drawAreaHeight; needScroll = gTrue; } else if (moveBottom && py + selectLRY < y0) { y0 = py + selectLRY; needScroll = gTrue; } if (needScroll) { scrollTo(x0, y0); } } } void PDFCore::moveSelection(int pg, int x, int y) { int newSelectULX, newSelectULY, newSelectLRX, newSelectLRY; // don't allow selections to span multiple pages if (pg != selectPage) { return; } // move appropriate edges of selection if (lastDragLeft) { if (x < selectLRX) { newSelectULX = x; newSelectLRX = selectLRX; } else { newSelectULX = selectLRX; newSelectLRX = x; lastDragLeft = gFalse; } } else { if (x > selectULX) { newSelectULX = selectULX; newSelectLRX = x; } else { newSelectULX = x; newSelectLRX = selectULX; lastDragLeft = gTrue; } } if (lastDragTop) { if (y < selectLRY) { newSelectULY = y; newSelectLRY = selectLRY; } else { newSelectULY = selectLRY; newSelectLRY = y; lastDragTop = gFalse; } } else { if (y > selectULY) { newSelectULY = selectULY; newSelectLRY = y; } else { newSelectULY = y; newSelectLRY = selectULY; lastDragTop = gTrue; } } // redraw the selection setSelection(selectPage, newSelectULX, newSelectULY, newSelectLRX, newSelectLRY); } void PDFCore::xorRectangle(int pg, int x0, int y0, int x1, int y1, SplashPattern *pattern, PDFCoreTile *oneTile) { Splash *splash; SplashPath *path; PDFCorePage *page; PDFCoreTile *tile; SplashCoord xx0, yy0, xx1, yy1; int xi, yi, wi, hi; int i; if ((page = findPage(pg))) { for (i = 0; i < page->tiles->getLength(); ++i) { tile = (PDFCoreTile *)page->tiles->get(i); if (!oneTile || tile == oneTile) { splash = new Splash(tile->bitmap, gFalse); splash->setFillPattern(pattern->copy()); xx0 = (SplashCoord)(x0 - tile->xMin); yy0 = (SplashCoord)(y0 - tile->yMin); xx1 = (SplashCoord)(x1 - tile->xMin); yy1 = (SplashCoord)(y1 - tile->yMin); path = new SplashPath(); path->moveTo(xx0, yy0); path->lineTo(xx1, yy0); path->lineTo(xx1, yy1); path->lineTo(xx0, yy1); path->close(); splash->xorFill(path, gTrue); delete path; delete splash; xi = x0 - tile->xMin; wi = x1 - x0; if (xi < 0) { wi += xi; xi = 0; } if (xi + wi > tile->bitmap->getWidth()) { wi = tile->bitmap->getWidth() - xi; } yi = y0 - tile->yMin; hi = y1 - y0; if (yi < 0) { hi += yi; yi = 0; } if (yi + hi > tile->bitmap->getHeight()) { hi = tile->bitmap->getHeight() - yi; } updateTileData(tile, xi, yi, wi, hi, gTrue); } } } delete pattern; } GBool PDFCore::getSelection(int *pg, double *ulx, double *uly, double *lrx, double *lry) { if (selectULX == selectLRX || selectULY == selectLRY) { return gFalse; } *pg = selectPage; cvtDevToUser(selectPage, selectULX, selectULY, ulx, uly); cvtDevToUser(selectPage, selectLRX, selectLRY, lrx, lry); return gTrue; } GString *PDFCore::extractText(int pg, double xMin, double yMin, double xMax, double yMax) { PDFCorePage *page; TextOutputDev *textOut; int x0, y0, x1, y1, t; GString *s; if (!doc->okToCopy()) { return NULL; } if ((page = findPage(pg))) { cvtUserToDev(pg, xMin, yMin, &x0, &y0); cvtUserToDev(pg, xMax, yMax, &x1, &y1); if (x0 > x1) { t = x0; x0 = x1; x1 = t; } if (y0 > y1) { t = y0; y0 = y1; y1 = t; } s = page->text->getText(x0, y0, x1, y1); } else { textOut = new TextOutputDev(NULL, gTrue, 0, gFalse, gFalse); if (textOut->isOk()) { doc->displayPage(textOut, pg, dpi, dpi, rotate, gFalse, gTrue, gFalse); textOut->cvtUserToDev(xMin, yMin, &x0, &y0); textOut->cvtUserToDev(xMax, yMax, &x1, &y1); if (x0 > x1) { t = x0; x0 = x1; x1 = t; } if (y0 > y1) { t = y0; y0 = y1; y1 = t; } s = textOut->getText(x0, y0, x1, y1); } else { s = new GString(); } delete textOut; } return s; } GBool PDFCore::find(char *s, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly) { Unicode *u; int len, i; GBool ret; // convert to Unicode len = (int)strlen(s); u = (Unicode *)gmallocn(len, sizeof(Unicode)); for (i = 0; i < len; ++i) { u[i] = (Unicode)(s[i] & 0xff); } ret = findU(u, len, caseSensitive, next, backward, wholeWord, onePageOnly); gfree(u); return ret; } GBool PDFCore::findU(Unicode *u, int len, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly) { TextOutputDev *textOut; double xMin, yMin, xMax, yMax; PDFCorePage *page; PDFCoreTile *tile; int pg; GBool startAtTop, startAtLast, stopAtLast; // check for zero-length string if (len == 0) { return gFalse; } setBusyCursor(gTrue); // search current page starting at previous result, current // selection, or top/bottom of page startAtTop = startAtLast = gFalse; xMin = yMin = xMax = yMax = 0; pg = topPage; if (next) { startAtLast = gTrue; } else if (selectULX != selectLRX && selectULY != selectLRY) { pg = selectPage; if (backward) { xMin = selectULX - 1; yMin = selectULY - 1; } else { xMin = selectULX + 1; yMin = selectULY + 1; } } else { startAtTop = gTrue; } if (!(page = findPage(pg))) { displayPage(pg, zoom, rotate, gTrue, gFalse); page = findPage(pg); } if (page->text->findText(u, len, startAtTop, gTrue, startAtLast, gFalse, caseSensitive, backward, wholeWord, &xMin, &yMin, &xMax, &yMax)) { goto found; } if (!onePageOnly) { // search following/previous pages textOut = new TextOutputDev(NULL, gTrue, 0, gFalse, gFalse); if (!textOut->isOk()) { delete textOut; goto notFound; } for (pg = backward ? pg - 1 : pg + 1; backward ? pg >= 1 : pg <= doc->getNumPages(); pg += backward ? -1 : 1) { doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse); if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, caseSensitive, backward, wholeWord, &xMin, &yMin, &xMax, &yMax)) { delete textOut; goto foundPage; } } // search previous/following pages for (pg = backward ? doc->getNumPages() : 1; backward ? pg > topPage : pg < topPage; pg += backward ? -1 : 1) { doc->displayPage(textOut, pg, 72, 72, 0, gFalse, gTrue, gFalse); if (textOut->findText(u, len, gTrue, gTrue, gFalse, gFalse, caseSensitive, backward, wholeWord, &xMin, &yMin, &xMax, &yMax)) { delete textOut; goto foundPage; } } delete textOut; } // search current page ending at previous result, current selection, // or bottom/top of page if (!startAtTop) { xMin = yMin = xMax = yMax = 0; if (next) { stopAtLast = gTrue; } else { stopAtLast = gFalse; xMax = selectLRX; yMax = selectLRY; } if (page->text->findText(u, len, gTrue, gFalse, gFalse, stopAtLast, caseSensitive, backward, wholeWord, &xMin, &yMin, &xMax, &yMax)) { goto found; } } // not found notFound: setBusyCursor(gFalse); return gFalse; // found on a different page foundPage: update(pg, scrollX, continuousMode ? -1 : 0, zoom, rotate, gFalse, gTrue, gTrue); page = findPage(pg); if (!page->text->findText(u, len, gTrue, gTrue, gFalse, gFalse, caseSensitive, backward, wholeWord, &xMin, &yMin, &xMax, &yMax)) { // this can happen if coalescing is bad goto notFound; } // found: change the selection found: tile = (PDFCoreTile *)page->tiles->get(0); setSelection(pg, (int)floor(xMin), (int)floor(yMin), (int)ceil(xMax), (int)ceil(yMax)); setBusyCursor(gFalse); return gTrue; } GBool PDFCore::cvtWindowToUser(int xw, int yw, int *pg, double *xu, double *yu) { PDFCorePage *page; PDFCoreTile *tile; int i; for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); if (xw >= page->xDest && xw < page->xDest + page->w && yw >= page->yDest && yw < page->yDest + page->h) { if (page->tiles->getLength() == 0) { break; } tile = (PDFCoreTile *)page->tiles->get(0); *pg = page->page; xw -= tile->xDest; yw -= tile->yDest; *xu = tile->ictm[0] * xw + tile->ictm[2] * yw + tile->ictm[4]; *yu = tile->ictm[1] * xw + tile->ictm[3] * yw + tile->ictm[5]; return gTrue; } } *pg = 0; *xu = *yu = 0; return gFalse; } GBool PDFCore::cvtWindowToDev(int xw, int yw, int *pg, int *xd, int *yd) { PDFCorePage *page; int i; for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); if (xw >= page->xDest && xw < page->xDest + page->w && yw >= page->yDest && yw < page->yDest + page->h) { *pg = page->page; *xd = xw - page->xDest; *yd = yw - page->yDest; return gTrue; } } *pg = 0; *xd = *yd = 0; return gFalse; } void PDFCore::cvtUserToWindow(int pg, double xu, double yu, int *xw, int *yw) { PDFCorePage *page; PDFCoreTile *tile; if ((page = findPage(pg)) && page->tiles->getLength() > 0) { tile = (PDFCoreTile *)page->tiles->get(0); } else if (curTile && curPage->page == pg) { tile = curTile; } else { tile = NULL; } if (tile) { *xw = tile->xDest + (int)(tile->ctm[0] * xu + tile->ctm[2] * yu + tile->ctm[4] + 0.5); *yw = tile->yDest + (int)(tile->ctm[1] * xu + tile->ctm[3] * yu + tile->ctm[5] + 0.5); } else { // this should never happen *xw = *yw = 0; } } void PDFCore::cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd) { PDFCorePage *page; PDFCoreTile *tile; double ctm[6]; if ((page = findPage(pg)) && page->tiles->getLength() > 0) { tile = (PDFCoreTile *)page->tiles->get(0); } else if (curTile && curPage->page == pg) { tile = curTile; } else { tile = NULL; } if (tile) { *xd = (int)(tile->xMin + tile->ctm[0] * xu + tile->ctm[2] * yu + tile->ctm[4] + 0.5); *yd = (int)(tile->yMin + tile->ctm[1] * xu + tile->ctm[3] * yu + tile->ctm[5] + 0.5); } else { doc->getCatalog()->getPage(pg)->getDefaultCTM(ctm, dpi, dpi, rotate, gFalse, out->upsideDown()); *xd = (int)(ctm[0] * xu + ctm[2] * yu + ctm[4] + 0.5); *yd = (int)(ctm[1] * xu + ctm[3] * yu + ctm[5] + 0.5); } } void PDFCore::cvtDevToWindow(int pg, int xd, int yd, int *xw, int *yw) { PDFCorePage *page; if ((page = findPage(pg))) { *xw = page->xDest + xd; *yw = page->yDest + yd; } else { // this should never happen *xw = *yw = 0; } } void PDFCore::cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu) { PDFCorePage *page; PDFCoreTile *tile; if ((page = findPage(pg)) && page->tiles->getLength() > 0) { tile = (PDFCoreTile *)page->tiles->get(0); } else if (curTile && curPage->page == pg) { tile = curTile; } else { tile = NULL; } if (tile) { xd -= tile->xMin; yd -= tile->yMin; *xu = tile->ictm[0] * xd + tile->ictm[2] * yd + tile->ictm[4]; *yu = tile->ictm[1] * xd + tile->ictm[3] * yd + tile->ictm[5]; } else { // this should never happen *xu = *yu = 0; } } void PDFCore::setReverseVideo(GBool reverseVideoA) { out->setReverseVideo(reverseVideoA); update(topPage, scrollX, scrollY, zoom, rotate, gTrue, gFalse, gFalse); } LinkAction *PDFCore::findLink(int pg, double x, double y) { PDFCorePage *page; if ((page = findPage(pg))) { return page->links ? page->links->find(x, y) : (LinkAction *)NULL; } return NULL; } PDFCorePage *PDFCore::findPage(int pg) { PDFCorePage *page; int i; for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); if (page->page == pg) { return page; } } return NULL; } void PDFCore::redrawCbk(void *data, int x0, int y0, int x1, int y1, GBool composited) { PDFCore *core = (PDFCore *)data; core->curTile->bitmap = core->out->getBitmap(); // the default CTM is set by the Gfx constructor; tile->ctm is // needed by the coordinate conversion functions (which may be // called during redraw) memcpy(core->curTile->ctm, core->out->getDefCTM(), 6 * sizeof(double)); memcpy(core->curTile->ictm, core->out->getDefICTM(), 6 * sizeof(double)); // the bitmap created by Gfx and SplashOutputDev can be a slightly // different size due to rounding errors if (x1 >= core->curTile->xMax - core->curTile->xMin) { x1 = core->curTile->xMax - core->curTile->xMin - 1; } if (y1 >= core->curTile->yMax - core->curTile->yMin) { y1 = core->curTile->yMax - core->curTile->yMin - 1; } core->clippedRedrawRect(core->curTile, x0, y0, core->curTile->xDest + x0, core->curTile->yDest + y0, x1 - x0 + 1, y1 - y0 + 1, 0, 0, core->drawAreaWidth, core->drawAreaHeight, gTrue, composited); } void PDFCore::redrawWindow(int x, int y, int width, int height, GBool needUpdate) { PDFCorePage *page; PDFCoreTile *tile; int xDest, yDest, w, i, j; if (pages->getLength() == 0) { redrawRect(NULL, 0, 0, x, y, width, height, gTrue); return; } for (i = 0; i < pages->getLength(); ++i) { page = (PDFCorePage *)pages->get(i); for (j = 0; j < page->tiles->getLength(); ++j) { tile = (PDFCoreTile *)page->tiles->get(j); if (tile->edges & pdfCoreTileTopEdge) { if (tile->edges & pdfCoreTileLeftEdge) { xDest = 0; } else { xDest = tile->xDest; } if (tile->edges & pdfCoreTileRightEdge) { w = drawAreaWidth - xDest; } else { w = tile->xDest + (tile->xMax - tile->xMin) - xDest; } clippedRedrawRect(NULL, 0, 0, xDest, 0, w, tile->yDest, x, y, width, height, gFalse); } if (tile->edges & pdfCoreTileBottomEdge) { if (tile->edges & pdfCoreTileLeftEdge) { xDest = 0; } else { xDest = tile->xDest; } if (tile->edges & pdfCoreTileRightEdge) { w = drawAreaWidth - xDest; } else { w = tile->xDest + (tile->xMax - tile->xMin) - xDest; } yDest = tile->yDest + (tile->yMax - tile->yMin); clippedRedrawRect(NULL, 0, 0, xDest, yDest, w, drawAreaHeight - yDest, x, y, width, height, gFalse); } else if ((tile->edges & pdfCoreTileBottomSpace) && i+1 < pages->getLength()) { if (tile->edges & pdfCoreTileLeftEdge) { xDest = 0; } else { xDest = tile->xDest; } if (tile->edges & pdfCoreTileRightEdge) { w = drawAreaWidth - xDest; } else { w = tile->xDest + (tile->xMax - tile->xMin) - xDest; } yDest = tile->yDest + (tile->yMax - tile->yMin); clippedRedrawRect(NULL, 0, 0, xDest, yDest, w, ((PDFCorePage *)pages->get(i+1))->yDest - yDest, x, y, width, height, gFalse); } if (tile->edges & pdfCoreTileLeftEdge) { clippedRedrawRect(NULL, 0, 0, 0, tile->yDest, tile->xDest, tile->yMax - tile->yMin, x, y, width, height, gFalse); } if (tile->edges & pdfCoreTileRightEdge) { xDest = tile->xDest + (tile->xMax - tile->xMin); clippedRedrawRect(NULL, 0, 0, xDest, tile->yDest, drawAreaWidth - xDest, tile->yMax - tile->yMin, x, y, width, height, gFalse); } clippedRedrawRect(tile, 0, 0, tile->xDest, tile->yDest, tile->bitmap->getWidth(), tile->bitmap->getHeight(), x, y, width, height, needUpdate); } } } PDFCoreTile *PDFCore::newTile(int xDestA, int yDestA) { return new PDFCoreTile(xDestA, yDestA); } void PDFCore::updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc, int width, int height, GBool composited) { } void PDFCore::clippedRedrawRect(PDFCoreTile *tile, int xSrc, int ySrc, int xDest, int yDest, int width, int height, int xClip, int yClip, int wClip, int hClip, GBool needUpdate, GBool composited) { if (tile && needUpdate) { updateTileData(tile, xSrc, ySrc, width, height, composited); } if (xDest < xClip) { xSrc += xClip - xDest; width -= xClip - xDest; xDest = xClip; } if (xDest + width > xClip + wClip) { width = xClip + wClip - xDest; } if (yDest < yClip) { ySrc += yClip - yDest; height -= yClip - yDest; yDest = yClip; } if (yDest + height > yClip + hClip) { height = yClip + hClip - yDest; } if (width > 0 && height > 0) { redrawRect(tile, xSrc, ySrc, xDest, yDest, width, height, composited); } } xpdf-3.03/xpdf/pdftoppm.cc0000644000076400007640000001350011622305345015013 0ustar dereknderekn//======================================================================== // // pdftoppm.cc // // Copyright 2003 Glyph & Cog, LLC // //======================================================================== #include #include #include "parseargs.h" #include "gmem.h" #include "GString.h" #include "GlobalParams.h" #include "Object.h" #include "PDFDoc.h" #include "SplashBitmap.h" #include "Splash.h" #include "SplashOutputDev.h" #include "config.h" static int firstPage = 1; static int lastPage = 0; static int resolution = 150; static GBool mono = gFalse; static GBool gray = gFalse; static char enableT1libStr[16] = ""; static char enableFreeTypeStr[16] = ""; static char antialiasStr[16] = ""; static char vectorAntialiasStr[16] = ""; static char ownerPassword[33] = ""; static char userPassword[33] = ""; static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to print"}, {"-l", argInt, &lastPage, 0, "last page to print"}, {"-r", argInt, &resolution, 0, "resolution, in DPI (default is 150)"}, {"-mono", argFlag, &mono, 0, "generate a monochrome PBM file"}, {"-gray", argFlag, &gray, 0, "generate a grayscale PGM file"}, #if HAVE_T1LIB_H {"-t1lib", argString, enableT1libStr, sizeof(enableT1libStr), "enable t1lib font rasterizer: yes, no"}, #endif #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H {"-freetype", argString, enableFreeTypeStr, sizeof(enableFreeTypeStr), "enable FreeType font rasterizer: yes, no"}, #endif {"-aa", argString, antialiasStr, sizeof(antialiasStr), "enable font anti-aliasing: yes, no"}, {"-aaVector", argString, vectorAntialiasStr, sizeof(vectorAntialiasStr), "enable vector anti-aliasing: yes, no"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; char *ppmRoot; GString *ppmFile; GString *ownerPW, *userPW; SplashColor paperColor; SplashOutputDev *splashOut; GBool ok; int exitCode; int pg; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (mono && gray) { ok = gFalse; } if (!ok || argc != 3 || printVersion || printHelp) { fprintf(stderr, "pdftoppm version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdftoppm", " ", argDesc); } goto err0; } fileName = new GString(argv[1]); ppmRoot = argv[2]; // read config file globalParams = new GlobalParams(cfgFileName); globalParams->setupBaseFonts(NULL); if (enableT1libStr[0]) { if (!globalParams->setEnableT1lib(enableT1libStr)) { fprintf(stderr, "Bad '-t1lib' value on command line\n"); } } if (enableFreeTypeStr[0]) { if (!globalParams->setEnableFreeType(enableFreeTypeStr)) { fprintf(stderr, "Bad '-freetype' value on command line\n"); } } if (antialiasStr[0]) { if (!globalParams->setAntialias(antialiasStr)) { fprintf(stderr, "Bad '-aa' value on command line\n"); } } if (vectorAntialiasStr[0]) { if (!globalParams->setVectorAntialias(vectorAntialiasStr)) { fprintf(stderr, "Bad '-aaVector' value on command line\n"); } } if (quiet) { globalParams->setErrQuiet(quiet); } // open PDF file if (ownerPassword[0]) { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0]) { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err1; } // get page range if (firstPage < 1) firstPage = 1; if (lastPage < 1 || lastPage > doc->getNumPages()) lastPage = doc->getNumPages(); // write PPM files if (mono) { paperColor[0] = 0xff; splashOut = new SplashOutputDev(splashModeMono1, 1, gFalse, paperColor); } else if (gray) { paperColor[0] = 0xff; splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, paperColor); } else { paperColor[0] = paperColor[1] = paperColor[2] = 0xff; splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor); } splashOut->startDoc(doc->getXRef()); for (pg = firstPage; pg <= lastPage; ++pg) { doc->displayPage(splashOut, pg, resolution, resolution, 0, gFalse, gTrue, gFalse); if (!strcmp(ppmRoot, "-")) { splashOut->getBitmap()->writePNMFile(stdout); } else { ppmFile = GString::format("{0:s}-{1:06d}.{2:s}", ppmRoot, pg, mono ? "pbm" : gray ? "pgm" : "ppm"); splashOut->getBitmap()->writePNMFile(ppmFile->getCString()); delete ppmFile; } } delete splashOut; exitCode = 0; // clean up err1: delete doc; delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } xpdf-3.03/xpdf/dblRightArrowDis.xbm0000644000076400007640000000046411622305345016602 0ustar dereknderekn#define dblRightArrowDis_width 16 #define dblRightArrowDis_height 15 static unsigned char dblRightArrowDis_bits[] = { 0x01, 0x01, 0x02, 0x02, 0x05, 0x05, 0x0a, 0x0a, 0x15, 0x15, 0x2a, 0x2a, 0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0x2a, 0x2a, 0x15, 0x15, 0x0a, 0x0a, 0x05, 0x05, 0x02, 0x02, 0x01, 0x01}; xpdf-3.03/xpdf/PDFDocEncoding.h0000644000076400007640000000052311622305345015533 0ustar dereknderekn//======================================================================== // // PDFDocEncoding.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PDFDOCENCODING_H #define PDFDOCENCODING_H #include "CharTypes.h" extern Unicode pdfDocEncoding[256]; #endif xpdf-3.03/xpdf/GfxFont.h0000644000076400007640000002520311622305345014402 0ustar dereknderekn//======================================================================== // // GfxFont.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFXFONT_H #define GFXFONT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "GString.h" #include "Object.h" #include "CharTypes.h" class Dict; class CMap; class CharCodeToUnicode; class FoFiTrueType; struct GfxFontCIDWidths; struct Base14FontMapEntry; //------------------------------------------------------------------------ // GfxFontType //------------------------------------------------------------------------ enum GfxFontType { //----- Gfx8BitFont fontUnknownType, fontType1, fontType1C, fontType1COT, fontType3, fontTrueType, fontTrueTypeOT, //----- GfxCIDFont fontCIDType0, fontCIDType0C, fontCIDType0COT, fontCIDType2, fontCIDType2OT }; //------------------------------------------------------------------------ // GfxFontCIDWidths //------------------------------------------------------------------------ struct GfxFontCIDWidthExcep { CID first; // this record applies to CID last; // CIDs .. double width; // char width }; struct GfxFontCIDWidthExcepV { CID first; // this record applies to CID last; // CIDs .. double height; // char height double vx, vy; // origin position }; struct GfxFontCIDWidths { double defWidth; // default char width double defHeight; // default char height double defVY; // default origin position GfxFontCIDWidthExcep *exceps; // exceptions int nExceps; // number of valid entries in exceps GfxFontCIDWidthExcepV * // exceptions for vertical font excepsV; int nExcepsV; // number of valid entries in excepsV }; //------------------------------------------------------------------------ // GfxFontLoc //------------------------------------------------------------------------ enum GfxFontLocType { gfxFontLocEmbedded, // font embedded in PDF file gfxFontLocExternal, // external font file gfxFontLocResident // font resident in PS printer }; class GfxFontLoc { public: GfxFontLoc(); ~GfxFontLoc(); GfxFontLocType locType; GfxFontType fontType; Ref embFontID; // embedded stream obj ID // (if locType == gfxFontLocEmbedded) GString *path; // font file path // (if locType == gfxFontLocExternal) // PS font name // (if locType == gfxFontLocResident) int fontNum; // for TrueType collections // (if locType == gfxFontLocExternal) GString *encoding; // PS font encoding, only for 16-bit fonts // (if locType == gfxFontLocResident) int wMode; // writing mode, only for 16-bit fonts // (if locType == gfxFontLocResident) int substIdx; // substitute font index // (if locType == gfxFontLocExternal, // and a Base-14 substitution was made) }; //------------------------------------------------------------------------ // GfxFont //------------------------------------------------------------------------ #define fontFixedWidth (1 << 0) #define fontSerif (1 << 1) #define fontSymbolic (1 << 2) #define fontItalic (1 << 6) #define fontBold (1 << 18) class GfxFont { public: // Build a GfxFont object. static GfxFont *makeFont(XRef *xref, char *tagA, Ref idA, Dict *fontDict); GfxFont(char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA); virtual ~GfxFont(); GBool isOk() { return ok; } // Get font tag. GString *getTag() { return tag; } // Get font dictionary ID. Ref *getID() { return &id; } // Does this font match the tag? GBool matches(char *tagA) { return !tag->cmp(tagA); } // Get the original font name (ignornig any munging that might have // been done to map to a canonical Base-14 font name). GString *getName() { return name; } // Get font type. GfxFontType getType() { return type; } virtual GBool isCIDFont() { return gFalse; } // Get embedded font ID, i.e., a ref for the font file stream. // Returns false if there is no embedded font. GBool getEmbeddedFontID(Ref *embID) { *embID = embFontID; return embFontID.num >= 0; } // Get the PostScript font name for the embedded font. Returns // NULL if there is no embedded font. GString *getEmbeddedFontName() { return embFontName; } // Get font descriptor flags. int getFlags() { return flags; } GBool isFixedWidth() { return flags & fontFixedWidth; } GBool isSerif() { return flags & fontSerif; } GBool isSymbolic() { return flags & fontSymbolic; } GBool isItalic() { return flags & fontItalic; } GBool isBold() { return flags & fontBold; } // Return the font matrix. double *getFontMatrix() { return fontMat; } // Return the font bounding box. double *getFontBBox() { return fontBBox; } // Return the ascent and descent values. double getAscent() { return ascent; } double getDescent() { return descent; } // Return the writing mode (0=horizontal, 1=vertical). virtual int getWMode() { return 0; } // Locate the font file for this font. If is true, includes PS // printer-resident fonts. Returns NULL on failure. GfxFontLoc *locateFont(XRef *xref, GBool ps); // Locate a Base-14 font file for a specified font name. static GfxFontLoc *locateBase14Font(GString *base14Name); // Read an embedded font file into a buffer. char *readEmbFontFile(XRef *xref, int *len); // Get the next char from a string of bytes, returning the // char , its Unicode mapping , its displacement vector // (, ), and its origin offset vector (, ). // is the number of entries available in , and is set to // the number actually used. Returns the number of bytes used by // the char code. virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, double *dx, double *dy, double *ox, double *oy) = 0; protected: static GfxFontType getFontType(XRef *xref, Dict *fontDict, Ref *embID); void readFontDescriptor(XRef *xref, Dict *fontDict); CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits, CharCodeToUnicode *ctu); static GfxFontLoc *getExternalFont(GString *path, GBool cid); GString *tag; // PDF font tag Ref id; // reference (used as unique ID) GString *name; // font name GfxFontType type; // type of font int flags; // font descriptor flags GString *embFontName; // name of embedded font Ref embFontID; // ref to embedded font file stream double fontMat[6]; // font matrix double fontBBox[4]; // font bounding box double missingWidth; // "default" width double ascent; // max height above baseline double descent; // max depth below baseline GBool ok; }; //------------------------------------------------------------------------ // Gfx8BitFont //------------------------------------------------------------------------ class Gfx8BitFont: public GfxFont { public: Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict); virtual ~Gfx8BitFont(); virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, double *dx, double *dy, double *ox, double *oy); // Return the encoding. char **getEncoding() { return enc; } // Return the Unicode map. CharCodeToUnicode *getToUnicode(); // Return the character name associated with . char *getCharName(int code) { return enc[code]; } // Returns true if the PDF font specified an encoding. GBool getHasEncoding() { return hasEncoding; } // Returns true if the PDF font specified MacRomanEncoding. GBool getUsesMacRomanEnc() { return usesMacRomanEnc; } // Get width of a character. double getWidth(Guchar c) { return widths[c]; } // Return a char code-to-GID mapping for the provided font file. // (This is only useful for TrueType fonts.) int *getCodeToGIDMap(FoFiTrueType *ff); // Return the Type 3 CharProc dictionary, or NULL if none. Dict *getCharProcs(); // Return the Type 3 CharProc for the character associated with . Object *getCharProc(int code, Object *proc); // Return the Type 3 Resources dictionary, or NULL if none. Dict *getResources(); private: Base14FontMapEntry *base14; // for Base-14 fonts only; NULL otherwise char *enc[256]; // char code --> char name char encFree[256]; // boolean for each char name: if set, // the string is malloc'ed CharCodeToUnicode *ctu; // char code --> Unicode GBool hasEncoding; GBool usesMacRomanEnc; double widths[256]; // character widths Object charProcs; // Type 3 CharProcs dictionary Object resources; // Type 3 Resources dictionary friend class GfxFont; }; //------------------------------------------------------------------------ // GfxCIDFont //------------------------------------------------------------------------ class GfxCIDFont: public GfxFont { public: GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GfxFontType typeA, Ref embFontIDA, Dict *fontDict); virtual ~GfxCIDFont(); virtual GBool isCIDFont() { return gTrue; } virtual int getNextChar(char *s, int len, CharCode *code, Unicode *u, int uSize, int *uLen, double *dx, double *dy, double *ox, double *oy); // Return the writing mode (0=horizontal, 1=vertical). virtual int getWMode(); // Return the Unicode map. CharCodeToUnicode *getToUnicode(); // Get the collection name (-). GString *getCollection(); // Return the CID-to-GID mapping table. These should only be called // if type is fontCIDType2. int *getCIDToGID() { return cidToGID; } int getCIDToGIDLen() { return cidToGIDLen; } private: GString *collection; // collection name CMap *cMap; // char code --> CID CharCodeToUnicode *ctu; // CID/char code --> Unicode GBool ctuUsesCharCode; // true: ctu maps char code to Unicode; // false: ctu maps CID to Unicode GfxFontCIDWidths widths; // character widths int *cidToGID; // CID --> GID mapping (for embedded // TrueType fonts) int cidToGIDLen; }; //------------------------------------------------------------------------ // GfxFontDict //------------------------------------------------------------------------ class GfxFontDict { public: // Build the font dictionary, given the PDF font dictionary. GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict); // Destructor. ~GfxFontDict(); // Get the specified font. GfxFont *lookup(char *tag); // Iterative access. int getNumFonts() { return numFonts; } GfxFont *getFont(int i) { return fonts[i]; } private: GfxFont **fonts; // list of fonts int numFonts; // number of fonts }; #endif xpdf-3.03/xpdf/backArrow.xbm0000644000076400007640000000043711622305345015303 0ustar dereknderekn#define backArrow_width 16 #define backArrow_height 15 static unsigned char backArrow_bits[] = { 0x80, 0x00, 0xc0, 0x00, 0xe0, 0x00, 0xf0, 0x00, 0xf8, 0x00, 0xfc, 0xcc, 0xfe, 0xcc, 0xff, 0xcc, 0xfe, 0xcc, 0xfc, 0xcc, 0xf8, 0xcc, 0xf0, 0x00, 0xe0, 0x00, 0xc0, 0x00, 0x80, 0x00}; xpdf-3.03/xpdf/Annot.cc0000644000076400007640000012340511622305345014247 0ustar dereknderekn//======================================================================== // // Annot.cc // // Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "GList.h" #include "Error.h" #include "Object.h" #include "Catalog.h" #include "Gfx.h" #include "GfxFont.h" #include "Lexer.h" #include "PDFDoc.h" #include "OptionalContent.h" #include "Annot.h" //------------------------------------------------------------------------ #define annotFlagHidden 0x0002 #define annotFlagPrint 0x0004 #define annotFlagNoView 0x0020 #define fieldFlagReadOnly 0x00000001 #define fieldFlagRequired 0x00000002 #define fieldFlagNoExport 0x00000004 #define fieldFlagMultiline 0x00001000 #define fieldFlagPassword 0x00002000 #define fieldFlagNoToggleToOff 0x00004000 #define fieldFlagRadio 0x00008000 #define fieldFlagPushbutton 0x00010000 #define fieldFlagCombo 0x00020000 #define fieldFlagEdit 0x00040000 #define fieldFlagSort 0x00080000 #define fieldFlagFileSelect 0x00100000 #define fieldFlagMultiSelect 0x00200000 #define fieldFlagDoNotSpellCheck 0x00400000 #define fieldFlagDoNotScroll 0x00800000 #define fieldFlagComb 0x01000000 #define fieldFlagRichText 0x02000000 #define fieldFlagRadiosInUnison 0x02000000 #define fieldFlagCommitOnSelChange 0x04000000 #define fieldQuadLeft 0 #define fieldQuadCenter 1 #define fieldQuadRight 2 // distance of Bezier control point from center for circle approximation // = (4 * (sqrt(2) - 1) / 3) * r #define bezierCircle 0.55228475 //------------------------------------------------------------------------ // AnnotBorderStyle //------------------------------------------------------------------------ AnnotBorderStyle::AnnotBorderStyle(AnnotBorderType typeA, double widthA, double *dashA, int dashLengthA, double rA, double gA, double bA) { type = typeA; width = widthA; dash = dashA; dashLength = dashLengthA; r = rA; g = gA; b = bA; } AnnotBorderStyle::~AnnotBorderStyle() { if (dash) { gfree(dash); } } //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ Annot::Annot(PDFDoc *docA, Dict *dict, Ref *refA) { Object apObj, asObj, obj1, obj2, obj3; AnnotBorderType borderType; double borderWidth; double *borderDash; int borderDashLength; double borderR, borderG, borderB; double t; int i; ok = gTrue; doc = docA; xref = doc->getXRef(); ref = *refA; type = NULL; appearanceState = NULL; appearBuf = NULL; borderStyle = NULL; //----- parse the type if (dict->lookup("Subtype", &obj1)->isName()) { type = new GString(obj1.getName()); } obj1.free(); //----- parse the rectangle if (dict->lookup("Rect", &obj1)->isArray() && obj1.arrayGetLength() == 4) { xMin = yMin = xMax = yMax = 0; if (obj1.arrayGet(0, &obj2)->isNum()) { xMin = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { yMin = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(2, &obj2)->isNum()) { xMax = obj2.getNum(); } obj2.free(); if (obj1.arrayGet(3, &obj2)->isNum()) { yMax = obj2.getNum(); } obj2.free(); if (xMin > xMax) { t = xMin; xMin = xMax; xMax = t; } if (yMin > yMax) { t = yMin; yMin = yMax; yMax = t; } } else { error(errSyntaxError, -1, "Bad bounding box for annotation"); ok = gFalse; } obj1.free(); //----- parse the flags if (dict->lookup("F", &obj1)->isInt()) { flags = obj1.getInt(); } else { flags = 0; } obj1.free(); //----- parse the border style borderType = annotBorderSolid; borderWidth = 1; borderDash = NULL; borderDashLength = 0; borderR = 0; borderG = 0; borderB = 1; if (dict->lookup("BS", &obj1)->isDict()) { if (obj1.dictLookup("S", &obj2)->isName()) { if (obj2.isName("S")) { borderType = annotBorderSolid; } else if (obj2.isName("D")) { borderType = annotBorderDashed; } else if (obj2.isName("B")) { borderType = annotBorderBeveled; } else if (obj2.isName("I")) { borderType = annotBorderInset; } else if (obj2.isName("U")) { borderType = annotBorderUnderlined; } } obj2.free(); if (obj1.dictLookup("W", &obj2)->isNum()) { borderWidth = obj2.getNum(); } obj2.free(); if (obj1.dictLookup("D", &obj2)->isArray()) { borderDashLength = obj2.arrayGetLength(); borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); } else { borderDash[i] = 1; } obj3.free(); } } obj2.free(); } else { obj1.free(); if (dict->lookup("Border", &obj1)->isArray()) { if (obj1.arrayGetLength() >= 3) { if (obj1.arrayGet(2, &obj2)->isNum()) { borderWidth = obj2.getNum(); } obj2.free(); if (obj1.arrayGetLength() >= 4) { if (obj1.arrayGet(3, &obj2)->isArray()) { borderType = annotBorderDashed; borderDashLength = obj2.arrayGetLength(); borderDash = (double *)gmallocn(borderDashLength, sizeof(double)); for (i = 0; i < borderDashLength; ++i) { if (obj2.arrayGet(i, &obj3)->isNum()) { borderDash[i] = obj3.getNum(); } else { borderDash[i] = 1; } obj3.free(); } } else { // Adobe draws no border at all if the last element is of // the wrong type. borderWidth = 0; } obj2.free(); } } } } obj1.free(); if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) { if (obj1.arrayGet(0, &obj2)->isNum()) { borderR = obj2.getNum(); } obj1.free(); if (obj1.arrayGet(1, &obj2)->isNum()) { borderG = obj2.getNum(); } obj1.free(); if (obj1.arrayGet(2, &obj2)->isNum()) { borderB = obj2.getNum(); } obj1.free(); } obj1.free(); borderStyle = new AnnotBorderStyle(borderType, borderWidth, borderDash, borderDashLength, borderR, borderG, borderB); //----- get the appearance state dict->lookup("AP", &apObj); dict->lookup("AS", &asObj); if (asObj.isName()) { appearanceState = new GString(asObj.getName()); } else if (apObj.isDict()) { apObj.dictLookup("N", &obj1); if (obj1.isDict() && obj1.dictGetLength() == 1) { appearanceState = new GString(obj1.dictGetKey(0)); } obj1.free(); } if (!appearanceState) { appearanceState = new GString("Off"); } asObj.free(); //----- get the annotation appearance if (apObj.isDict()) { apObj.dictLookup("N", &obj1); apObj.dictLookupNF("N", &obj2); if (obj1.isDict()) { if (obj1.dictLookupNF(appearanceState->getCString(), &obj3)->isRef()) { obj3.copy(&appearance); } obj3.free(); } else if (obj2.isRef()) { obj2.copy(&appearance); } obj1.free(); obj2.free(); } apObj.free(); //----- get the optional content entry dict->lookupNF("OC", &ocObj); } Annot::~Annot() { if (type) { delete type; } if (appearanceState) { delete appearanceState; } appearance.free(); if (appearBuf) { delete appearBuf; } if (borderStyle) { delete borderStyle; } ocObj.free(); } void Annot::generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm) { Object mkObj, ftObj, appearDict, drObj, obj1, obj2, obj3; Dict *mkDict; MemStream *appearStream; GfxFontDict *fontDict; GBool hasCaption; double w, dx, dy, r; double *dash; GString *caption, *da; GString **text; GBool *selection; int rot, dashLength, ff, quadding, comb, nOptions, topIdx, i, j; // must be a Widget annotation if (type && type->cmp("Widget")) { return; } appearBuf = new GString(); // get the appearance characteristics (MK) dictionary if (annot->lookup("MK", &mkObj)->isDict()) { mkDict = mkObj.getDict(); } else { mkDict = NULL; } // draw the background if (mkDict) { if (mkDict->lookup("BG", &obj1)->isArray() && obj1.arrayGetLength() > 0) { setColor(obj1.getArray(), gTrue, 0); appearBuf->appendf("0 0 {0:.2f} {1:.2f} re f\n", xMax - xMin, yMax - yMin); } obj1.free(); } // get the field type fieldLookup(field, acroForm, "FT", &ftObj); // get the field flags (Ff) value if (fieldLookup(field, acroForm, "Ff", &obj1)->isInt()) { ff = obj1.getInt(); } else { ff = 0; } obj1.free(); // draw the border if (mkDict) { w = borderStyle->getWidth(); if (w > 0) { mkDict->lookup("BC", &obj1); if (!(obj1.isArray() && obj1.arrayGetLength() > 0)) { mkDict->lookup("BG", &obj1); } if (obj1.isArray() && obj1.arrayGetLength() > 0) { dx = xMax - xMin; dy = yMax - yMin; // radio buttons with no caption have a round border hasCaption = mkDict->lookup("CA", &obj2)->isString(); obj2.free(); if (ftObj.isName("Btn") && (ff & fieldFlagRadio) && !hasCaption) { r = 0.5 * (dx < dy ? dx : dy); switch (borderStyle->getType()) { case annotBorderDashed: appearBuf->append("["); borderStyle->getDash(&dash, &dashLength); for (i = 0; i < dashLength; ++i) { appearBuf->appendf(" {0:.2f}", dash[i]); } appearBuf->append("] 0 d\n"); // fall through to the solid case case annotBorderSolid: case annotBorderUnderlined: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); drawCircle(0.5 * dx, 0.5 * dy, r - 0.5 * w, gFalse); break; case annotBorderBeveled: case annotBorderInset: appearBuf->appendf("{0:.2f} w\n", 0.5 * w); setColor(obj1.getArray(), gFalse, 0); drawCircle(0.5 * dx, 0.5 * dy, r - 0.25 * w, gFalse); setColor(obj1.getArray(), gFalse, borderStyle->getType() == annotBorderBeveled ? 1 : -1); drawCircleTopLeft(0.5 * dx, 0.5 * dy, r - 0.75 * w); setColor(obj1.getArray(), gFalse, borderStyle->getType() == annotBorderBeveled ? -1 : 1); drawCircleBottomRight(0.5 * dx, 0.5 * dy, r - 0.75 * w); break; } } else { switch (borderStyle->getType()) { case annotBorderDashed: appearBuf->append("["); borderStyle->getDash(&dash, &dashLength); for (i = 0; i < dashLength; ++i) { appearBuf->appendf(" {0:.2f}", dash[i]); } appearBuf->append("] 0 d\n"); // fall through to the solid case case annotBorderSolid: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re s\n", 0.5 * w, dx - w, dy - w); break; case annotBorderBeveled: case annotBorderInset: setColor(obj1.getArray(), gTrue, borderStyle->getType() == annotBorderBeveled ? 1 : -1); appearBuf->append("0 0 m\n"); appearBuf->appendf("0 {0:.2f} l\n", dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); appearBuf->appendf("{0:.2f} {1:.2f} l\n", w, dy - w); appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); appearBuf->append("f\n"); setColor(obj1.getArray(), gTrue, borderStyle->getType() == annotBorderBeveled ? -1 : 1); appearBuf->append("0 0 m\n"); appearBuf->appendf("{0:.2f} 0 l\n", dx); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx, dy); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, dy - w); appearBuf->appendf("{0:.2f} {1:.2f} l\n", dx - w, w); appearBuf->appendf("{0:.2f} {0:.2f} l\n", w); appearBuf->append("f\n"); break; case annotBorderUnderlined: appearBuf->appendf("{0:.2f} w\n", w); setColor(obj1.getArray(), gFalse, 0); appearBuf->appendf("0 0 m {0:.2f} 0 l s\n", dx); break; } // clip to the inside of the border appearBuf->appendf("{0:.2f} {0:.2f} {1:.2f} {2:.2f} re W n\n", w, dx - 2 * w, dy - 2 * w); } } obj1.free(); } } // get the resource dictionary fieldLookup(field, acroForm, "DR", &drObj); // build the font dictionary if (drObj.isDict() && drObj.dictLookup("Font", &obj1)->isDict()) { fontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict()); } else { fontDict = NULL; } obj1.free(); // get the default appearance string if (fieldLookup(field, acroForm, "DA", &obj1)->isNull()) { obj1.free(); acroForm->lookup("DA", &obj1); } if (obj1.isString()) { da = obj1.getString()->copy(); } else { da = NULL; } obj1.free(); // get the rotation value rot = 0; if (mkDict) { if (mkDict->lookup("R", &obj1)->isInt()) { rot = obj1.getInt(); } obj1.free(); } // draw the field contents if (ftObj.isName("Btn")) { caption = NULL; if (mkDict) { if (mkDict->lookup("CA", &obj1)->isString()) { caption = obj1.getString()->copy(); } obj1.free(); } // radio button if (ff & fieldFlagRadio) { //~ Acrobat doesn't draw a caption if there is no AP dict (?) if (fieldLookup(field, acroForm, "V", &obj1) ->isName(appearanceState->getCString())) { if (caption) { drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gTrue, rot); } else { if (mkDict) { if (mkDict->lookup("BC", &obj2)->isArray() && obj2.arrayGetLength() > 0) { dx = xMax - xMin; dy = yMax - yMin; setColor(obj2.getArray(), gTrue, 0); drawCircle(0.5 * dx, 0.5 * dy, 0.2 * (dx < dy ? dx : dy), gTrue); } obj2.free(); } } } obj1.free(); // pushbutton } else if (ff & fieldFlagPushbutton) { if (caption) { drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gFalse, rot); } // checkbox } else { fieldLookup(field, acroForm, "V", &obj1); if (obj1.isName() && !obj1.isName("Off")) { if (!caption) { caption = new GString("3"); // ZapfDingbats checkmark } drawText(caption, da, fontDict, gFalse, 0, fieldQuadCenter, gFalse, gTrue, rot); } obj1.free(); } if (caption) { delete caption; } } else if (ftObj.isName("Tx")) { //~ value strings can be Unicode if (!fieldLookup(field, acroForm, "V", &obj1)->isString()) { obj1.free(); fieldLookup(field, acroForm, "DV", &obj1); } if (obj1.isString()) { if (fieldLookup(field, acroForm, "Q", &obj2)->isInt()) { quadding = obj2.getInt(); } else { quadding = fieldQuadLeft; } obj2.free(); comb = 0; if (ff & fieldFlagComb) { if (fieldLookup(field, acroForm, "MaxLen", &obj2)->isInt()) { comb = obj2.getInt(); } obj2.free(); } drawText(obj1.getString(), da, fontDict, ff & fieldFlagMultiline, comb, quadding, gTrue, gFalse, rot); } obj1.free(); } else if (ftObj.isName("Ch")) { //~ value/option strings can be Unicode if (fieldLookup(field, acroForm, "Q", &obj1)->isInt()) { quadding = obj1.getInt(); } else { quadding = fieldQuadLeft; } obj1.free(); // combo box if (ff & fieldFlagCombo) { if (fieldLookup(field, acroForm, "V", &obj1)->isString()) { drawText(obj1.getString(), da, fontDict, gFalse, 0, quadding, gTrue, gFalse, rot); //~ Acrobat draws a popup icon on the right side } obj1.free(); // list box } else { if (field->lookup("Opt", &obj1)->isArray()) { nOptions = obj1.arrayGetLength(); // get the option text text = (GString **)gmallocn(nOptions, sizeof(GString *)); for (i = 0; i < nOptions; ++i) { text[i] = NULL; obj1.arrayGet(i, &obj2); if (obj2.isString()) { text[i] = obj2.getString()->copy(); } else if (obj2.isArray() && obj2.arrayGetLength() == 2) { if (obj2.arrayGet(1, &obj3)->isString()) { text[i] = obj3.getString()->copy(); } obj3.free(); } obj2.free(); if (!text[i]) { text[i] = new GString(); } } // get the selected option(s) selection = (GBool *)gmallocn(nOptions, sizeof(GBool)); //~ need to use the I field in addition to the V field fieldLookup(field, acroForm, "V", &obj2); for (i = 0; i < nOptions; ++i) { selection[i] = gFalse; if (obj2.isString()) { if (!obj2.getString()->cmp(text[i])) { selection[i] = gTrue; } } else if (obj2.isArray()) { for (j = 0; j < obj2.arrayGetLength(); ++j) { if (obj2.arrayGet(j, &obj3)->isString() && !obj3.getString()->cmp(text[i])) { selection[i] = gTrue; } obj3.free(); } } } obj2.free(); // get the top index if (field->lookup("TI", &obj2)->isInt()) { topIdx = obj2.getInt(); } else { topIdx = 0; } obj2.free(); // draw the text drawListBox(text, selection, nOptions, topIdx, da, fontDict, quadding); for (i = 0; i < nOptions; ++i) { delete text[i]; } gfree(text); gfree(selection); } obj1.free(); } } else if (ftObj.isName("Sig")) { //~unimp } else { error(errSyntaxError, -1, "Unknown field type"); } if (da) { delete da; } // build the appearance stream dictionary appearDict.initDict(doc->getXRef()); appearDict.dictAdd(copyString("Length"), obj1.initInt(appearBuf->getLength())); appearDict.dictAdd(copyString("Subtype"), obj1.initName("Form")); obj1.initArray(doc->getXRef()); obj1.arrayAdd(obj2.initReal(0)); obj1.arrayAdd(obj2.initReal(0)); obj1.arrayAdd(obj2.initReal(xMax - xMin)); obj1.arrayAdd(obj2.initReal(yMax - yMin)); appearDict.dictAdd(copyString("BBox"), &obj1); // set the resource dictionary if (drObj.isDict()) { appearDict.dictAdd(copyString("Resources"), drObj.copy(&obj1)); } drObj.free(); // build the appearance stream appearStream = new MemStream(appearBuf->getCString(), 0, appearBuf->getLength(), &appearDict); appearance.free(); appearance.initStream(appearStream); if (fontDict) { delete fontDict; } ftObj.free(); mkObj.free(); } // Set the current fill or stroke color, based on (which should // have 1, 3, or 4 elements). If is +1, color is brightened; // if is -1, color is darkened; otherwise color is not // modified. void Annot::setColor(Array *a, GBool fill, int adjust) { Object obj1; double color[4]; int nComps, i; nComps = a->getLength(); if (nComps > 4) { nComps = 4; } for (i = 0; i < nComps && i < 4; ++i) { if (a->get(i, &obj1)->isNum()) { color[i] = obj1.getNum(); } else { color[i] = 0; } obj1.free(); } if (nComps == 4) { adjust = -adjust; } if (adjust > 0) { for (i = 0; i < nComps; ++i) { color[i] = 0.5 * color[i] + 0.5; } } else if (adjust < 0) { for (i = 0; i < nComps; ++i) { color[i] = 0.5 * color[i]; } } if (nComps == 4) { appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:c}\n", color[0], color[1], color[2], color[3], fill ? 'k' : 'K'); } else if (nComps == 3) { appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:s}\n", color[0], color[1], color[2], fill ? "rg" : "RG"); } else { appearBuf->appendf("{0:.2f} {1:c}\n", color[0], fill ? 'g' : 'G'); } } // Draw the variable text or caption for a field. void Annot::drawText(GString *text, GString *da, GfxFontDict *fontDict, GBool multiline, int comb, int quadding, GBool txField, GBool forceZapfDingbats, int rot) { GString *text2; GList *daToks; GString *tok; GfxFont *font; double dx, dy; double fontSize, fontSize2, border, x, xPrev, y, w, w2, wMax; int tfPos, tmPos, i, j, k, c; //~ if there is no MK entry, this should use the existing content stream, //~ and only replace the marked content portion of it //~ (this is only relevant for Tx fields) // check for a Unicode string //~ this currently drops all non-Latin1 characters if (text->getLength() >= 2 && text->getChar(0) == '\xfe' && text->getChar(1) == '\xff') { text2 = new GString(); for (i = 2; i+1 < text->getLength(); i += 2) { c = ((text->getChar(i) & 0xff) << 8) + (text->getChar(i+1) & 0xff); if (c <= 0xff) { text2->append((char)c); } else { text2->append('?'); } } } else { text2 = text; } // parse the default appearance string tfPos = tmPos = -1; if (da) { daToks = new GList(); i = 0; while (i < da->getLength()) { while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { ++i; } if (i < da->getLength()) { for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) ; daToks->append(new GString(da, i, j - i)); i = j; } } for (i = 2; i < daToks->getLength(); ++i) { if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { tfPos = i - 2; } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) { tmPos = i - 6; } } } else { daToks = NULL; } // force ZapfDingbats //~ this should create the font if needed (?) if (forceZapfDingbats) { if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos); if (tok->cmp("/ZaDb")) { tok->clear(); tok->append("/ZaDb"); } } } // get the font and font size font = NULL; fontSize = 0; if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos); if (tok->getLength() >= 1 && tok->getChar(0) == '/') { if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) { error(errSyntaxError, -1, "Unknown font in field's DA string"); } } else { error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string"); } tok = (GString *)daToks->get(tfPos + 1); fontSize = atof(tok->getCString()); } else { error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string"); } // get the border width border = borderStyle->getWidth(); // setup if (txField) { appearBuf->append("/Tx BMC\n"); } appearBuf->append("q\n"); if (rot == 90) { appearBuf->appendf("0 1 -1 0 {0:.2f} 0 cm\n", xMax - xMin); dx = yMax - yMin; dy = xMax - xMin; } else if (rot == 180) { appearBuf->appendf("-1 0 0 -1 {0:.2f} {1:.2f} cm\n", xMax - xMin, yMax - yMin); dx = xMax - yMax; dy = yMax - yMin; } else if (rot == 270) { appearBuf->appendf("0 -1 1 0 0 {0:.2f} cm\n", yMax - yMin); dx = yMax - yMin; dy = xMax - xMin; } else { // assume rot == 0 dx = xMax - xMin; dy = yMax - yMin; } appearBuf->append("BT\n"); // multi-line text if (multiline) { // note: the comb flag is ignored in multiline mode wMax = dx - 2 * border - 4; // compute font autosize if (fontSize == 0) { for (fontSize = 20; fontSize > 1; --fontSize) { y = dy - 3; w2 = 0; i = 0; while (i < text2->getLength()) { getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k); if (w > w2) { w2 = w; } i = k; y -= fontSize; } // approximate the descender for the last line if (y >= 0.33 * fontSize) { break; } } if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); tok->appendf("{0:.2f}", fontSize); } } // starting y coordinate // (note: each line of text starts with a Td operator that moves // down a line) y = dy - 3; // set the font matrix if (tmPos >= 0) { tok = (GString *)daToks->get(tmPos + 4); tok->clear(); tok->append('0'); tok = (GString *)daToks->get(tmPos + 5); tok->clear(); tok->appendf("{0:.2f}", y); } // write the DA string if (daToks) { for (i = 0; i < daToks->getLength(); ++i) { appearBuf->append((GString *)daToks->get(i))->append(' '); } } // write the font matrix (if not part of the DA string) if (tmPos < 0) { appearBuf->appendf("1 0 0 1 0 {0:.2f} Tm\n", y); } // write a series of lines of text i = 0; xPrev = 0; while (i < text2->getLength()) { getNextLine(text2, i, font, fontSize, wMax, &j, &w, &k); // compute text start position switch (quadding) { case fieldQuadLeft: default: x = border + 2; break; case fieldQuadCenter: x = (dx - w) / 2; break; case fieldQuadRight: x = dx - border - 2 - w; break; } // draw the line appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize); appearBuf->append('('); for (; i < j; ++i) { c = text2->getChar(i) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append(c); } else if (c < 0x20 || c >= 0x80) { appearBuf->appendf("\\{0:03o}", c); } else { appearBuf->append(c); } } appearBuf->append(") Tj\n"); // next line i = k; xPrev = x; } // single-line text } else { //~ replace newlines with spaces? - what does Acrobat do? // comb formatting if (comb > 0) { // compute comb spacing w = (dx - 2 * border) / comb; // compute font autosize if (fontSize == 0) { fontSize = dy - 2 * border; if (w < fontSize) { fontSize = w; } fontSize = floor(fontSize); if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); tok->appendf("{0:.2f}", fontSize); } } // compute text start position switch (quadding) { case fieldQuadLeft: default: x = border + 2; break; case fieldQuadCenter: x = border + 2 + 0.5 * (comb - text2->getLength()) * w; break; case fieldQuadRight: x = border + 2 + (comb - text2->getLength()) * w; break; } y = 0.5 * dy - 0.4 * fontSize; // set the font matrix if (tmPos >= 0) { tok = (GString *)daToks->get(tmPos + 4); tok->clear(); tok->appendf("{0:.2f}", x); tok = (GString *)daToks->get(tmPos + 5); tok->clear(); tok->appendf("{0:.2f}", y); } // write the DA string if (daToks) { for (i = 0; i < daToks->getLength(); ++i) { appearBuf->append((GString *)daToks->get(i))->append(' '); } } // write the font matrix (if not part of the DA string) if (tmPos < 0) { appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); } // write the text string //~ this should center (instead of left-justify) each character within //~ its comb cell for (i = 0; i < text2->getLength(); ++i) { if (i > 0) { appearBuf->appendf("{0:.2f} 0 Td\n", w); } appearBuf->append('('); c = text2->getChar(i) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append(c); } else if (c < 0x20 || c >= 0x80) { appearBuf->appendf("{0:.2f} 0 Td\n", w); } else { appearBuf->append(c); } appearBuf->append(") Tj\n"); } // regular (non-comb) formatting } else { // compute string width if (font && !font->isCIDFont()) { w = 0; for (i = 0; i < text2->getLength(); ++i) { w += ((Gfx8BitFont *)font)->getWidth(text2->getChar(i)); } } else { // otherwise, make a crude estimate w = text2->getLength() * 0.5; } // compute font autosize if (fontSize == 0) { fontSize = dy - 2 * border; fontSize2 = (dx - 4 - 2 * border) / w; if (fontSize2 < fontSize) { fontSize = fontSize2; } fontSize = floor(fontSize); if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); tok->appendf("{0:.2f}", fontSize); } } // compute text start position w *= fontSize; switch (quadding) { case fieldQuadLeft: default: x = border + 2; break; case fieldQuadCenter: x = (dx - w) / 2; break; case fieldQuadRight: x = dx - border - 2 - w; break; } y = 0.5 * dy - 0.4 * fontSize; // set the font matrix if (tmPos >= 0) { tok = (GString *)daToks->get(tmPos + 4); tok->clear(); tok->appendf("{0:.2f}", x); tok = (GString *)daToks->get(tmPos + 5); tok->clear(); tok->appendf("{0:.2f}", y); } // write the DA string if (daToks) { for (i = 0; i < daToks->getLength(); ++i) { appearBuf->append((GString *)daToks->get(i))->append(' '); } } // write the font matrix (if not part of the DA string) if (tmPos < 0) { appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); } // write the text string appearBuf->append('('); for (i = 0; i < text2->getLength(); ++i) { c = text2->getChar(i) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append(c); } else if (c < 0x20 || c >= 0x80) { appearBuf->appendf("\\{0:03o}", c); } else { appearBuf->append(c); } } appearBuf->append(") Tj\n"); } } // cleanup appearBuf->append("ET\n"); appearBuf->append("Q\n"); if (txField) { appearBuf->append("EMC\n"); } if (daToks) { deleteGList(daToks, GString); } if (text2 != text) { delete text2; } } // Draw the variable text or caption for a field. void Annot::drawListBox(GString **text, GBool *selection, int nOptions, int topIdx, GString *da, GfxFontDict *fontDict, GBool quadding) { GList *daToks; GString *tok; GfxFont *font; double fontSize, fontSize2, border, x, y, w, wMax; int tfPos, tmPos, i, j, c; //~ if there is no MK entry, this should use the existing content stream, //~ and only replace the marked content portion of it //~ (this is only relevant for Tx fields) // parse the default appearance string tfPos = tmPos = -1; if (da) { daToks = new GList(); i = 0; while (i < da->getLength()) { while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { ++i; } if (i < da->getLength()) { for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) ; daToks->append(new GString(da, i, j - i)); i = j; } } for (i = 2; i < daToks->getLength(); ++i) { if (i >= 2 && !((GString *)daToks->get(i))->cmp("Tf")) { tfPos = i - 2; } else if (i >= 6 && !((GString *)daToks->get(i))->cmp("Tm")) { tmPos = i - 6; } } } else { daToks = NULL; } // get the font and font size font = NULL; fontSize = 0; if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos); if (tok->getLength() >= 1 && tok->getChar(0) == '/') { if (!fontDict || !(font = fontDict->lookup(tok->getCString() + 1))) { error(errSyntaxError, -1, "Unknown font in field's DA string"); } } else { error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string"); } tok = (GString *)daToks->get(tfPos + 1); fontSize = atof(tok->getCString()); } else { error(errSyntaxError, -1, "Missing 'Tf' operator in field's DA string"); } // get the border width border = borderStyle->getWidth(); // compute font autosize if (fontSize == 0) { wMax = 0; for (i = 0; i < nOptions; ++i) { if (font && !font->isCIDFont()) { w = 0; for (j = 0; j < text[i]->getLength(); ++j) { w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); } } else { // otherwise, make a crude estimate w = text[i]->getLength() * 0.5; } if (w > wMax) { wMax = w; } } fontSize = yMax - yMin - 2 * border; fontSize2 = (xMax - xMin - 4 - 2 * border) / wMax; if (fontSize2 < fontSize) { fontSize = fontSize2; } fontSize = floor(fontSize); if (tfPos >= 0) { tok = (GString *)daToks->get(tfPos + 1); tok->clear(); tok->appendf("{0:.2f}", fontSize); } } // draw the text y = yMax - yMin - 1.1 * fontSize; for (i = topIdx; i < nOptions; ++i) { // setup appearBuf->append("q\n"); // draw the background if selected if (selection[i]) { appearBuf->append("0 g f\n"); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re f\n", border, y - 0.2 * fontSize, xMax - xMin - 2 * border, 1.1 * fontSize); } // setup appearBuf->append("BT\n"); // compute string width if (font && !font->isCIDFont()) { w = 0; for (j = 0; j < text[i]->getLength(); ++j) { w += ((Gfx8BitFont *)font)->getWidth(text[i]->getChar(j)); } } else { // otherwise, make a crude estimate w = text[i]->getLength() * 0.5; } // compute text start position w *= fontSize; switch (quadding) { case fieldQuadLeft: default: x = border + 2; break; case fieldQuadCenter: x = (xMax - xMin - w) / 2; break; case fieldQuadRight: x = xMax - xMin - border - 2 - w; break; } // set the font matrix if (tmPos >= 0) { tok = (GString *)daToks->get(tmPos + 4); tok->clear(); tok->appendf("{0:.2f}", x); tok = (GString *)daToks->get(tmPos + 5); tok->clear(); tok->appendf("{0:.2f}", y); } // write the DA string if (daToks) { for (j = 0; j < daToks->getLength(); ++j) { appearBuf->append((GString *)daToks->get(j))->append(' '); } } // write the font matrix (if not part of the DA string) if (tmPos < 0) { appearBuf->appendf("1 0 0 1 {0:.2f} {1:.2f} Tm\n", x, y); } // change the text color if selected if (selection[i]) { appearBuf->append("1 g\n"); } // write the text string appearBuf->append('('); for (j = 0; j < text[i]->getLength(); ++j) { c = text[i]->getChar(j) & 0xff; if (c == '(' || c == ')' || c == '\\') { appearBuf->append('\\'); appearBuf->append(c); } else if (c < 0x20 || c >= 0x80) { appearBuf->appendf("\\{0:03o}", c); } else { appearBuf->append(c); } } appearBuf->append(") Tj\n"); // cleanup appearBuf->append("ET\n"); appearBuf->append("Q\n"); // next line y -= 1.1 * fontSize; } if (daToks) { deleteGList(daToks, GString); } } // Figure out how much text will fit on the next line. Returns: // *end = one past the last character to be included // *width = width of the characters start .. end-1 // *next = index of first character on the following line void Annot::getNextLine(GString *text, int start, GfxFont *font, double fontSize, double wMax, int *end, double *width, int *next) { double w, dw; int j, k, c; // figure out how much text will fit on the line //~ what does Adobe do with tabs? w = 0; for (j = start; j < text->getLength() && w <= wMax; ++j) { c = text->getChar(j) & 0xff; if (c == 0x0a || c == 0x0d) { break; } if (font && !font->isCIDFont()) { dw = ((Gfx8BitFont *)font)->getWidth(c) * fontSize; } else { // otherwise, make a crude estimate dw = 0.5 * fontSize; } w += dw; } if (w > wMax) { for (k = j; k > start && text->getChar(k-1) != ' '; --k) ; for (; k > start && text->getChar(k-1) == ' '; --k) ; if (k > start) { j = k; } if (j == start) { // handle the pathological case where the first character is // too wide to fit on the line all by itself j = start + 1; } } *end = j; // compute the width w = 0; for (k = start; k < j; ++k) { if (font && !font->isCIDFont()) { dw = ((Gfx8BitFont *)font)->getWidth(text->getChar(k)) * fontSize; } else { // otherwise, make a crude estimate dw = 0.5 * fontSize; } w += dw; } *width = w; // next line while (j < text->getLength() && text->getChar(j) == ' ') { ++j; } if (j < text->getLength() && text->getChar(j) == 0x0d) { ++j; } if (j < text->getLength() && text->getChar(j) == 0x0a) { ++j; } *next = j; } // Draw an (approximate) circle of radius centered at (, ). // If is true, the circle is filled; otherwise it is stroked. void Annot::drawCircle(double cx, double cy, double r, GBool fill) { appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r, cy); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + r, cy + bezierCircle * r, cx + bezierCircle * r, cy + r, cx, cy + r); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - bezierCircle * r, cy + r, cx - r, cy + bezierCircle * r, cx - r, cy); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - r, cy - bezierCircle * r, cx - bezierCircle * r, cy - r, cx, cy - r); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + bezierCircle * r, cy - r, cx + r, cy - bezierCircle * r, cx + r, cy); appearBuf->append(fill ? "f\n" : "s\n"); } // Draw the top-left half of an (approximate) circle of radius // centered at (, ). void Annot::drawCircleTopLeft(double cx, double cy, double r) { double r2; r2 = r / sqrt(2.0); appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx + r2, cy + r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - (1 - bezierCircle) * r2, cy + (1 + bezierCircle) * r2, cx - r2, cy + r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx - (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx - r2, cy - r2); appearBuf->append("S\n"); } // Draw the bottom-right half of an (approximate) circle of radius // centered at (, ). void Annot::drawCircleBottomRight(double cx, double cy, double r) { double r2; r2 = r / sqrt(2.0); appearBuf->appendf("{0:.2f} {1:.2f} m\n", cx - r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx - (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + (1 - bezierCircle) * r2, cy - (1 + bezierCircle) * r2, cx + r2, cy - r2); appearBuf->appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} {4:.2f} {5:.2f} c\n", cx + (1 + bezierCircle) * r2, cy - (1 - bezierCircle) * r2, cx + (1 + bezierCircle) * r2, cy + (1 - bezierCircle) * r2, cx + r2, cy + r2); appearBuf->append("S\n"); } // Look up an inheritable field dictionary entry. Object *Annot::fieldLookup(Dict *field, Dict *acroForm, const char *key, Object *obj) { Dict *dict; Object parent; dict = field; if (!dict->lookup(key, obj)->isNull()) { return obj; } obj->free(); if (dict->lookup("Parent", &parent)->isDict()) { fieldLookup(parent.getDict(), acroForm, key, obj); } else if (acroForm) { // some fields don't specify a parent, so we check the AcroForm // dictionary just in case fieldLookup(acroForm, NULL, key, obj); } else { obj->initNull(); } parent.free(); return obj; } void Annot::draw(Gfx *gfx, GBool printing) { Object obj; GBool oc, isLink; // check the flags if ((flags & annotFlagHidden) || (printing && !(flags & annotFlagPrint)) || (!printing && (flags & annotFlagNoView))) { return; } // check the optional content entry if (doc->getOptionalContent()->evalOCObject(&ocObj, &oc) && !oc) { return; } // draw the appearance stream isLink = type && !type->cmp("Link"); appearance.fetch(doc->getXRef(), &obj); gfx->drawAnnot(&obj, isLink ? borderStyle : (AnnotBorderStyle *)NULL, xMin, yMin, xMax, yMax); obj.free(); } Object *Annot::getObject(Object *obj) { if (ref.num >= 0) { xref->fetch(ref.num, ref.gen, obj); } else { obj->initNull(); } return obj; } //------------------------------------------------------------------------ // Annots //------------------------------------------------------------------------ Annots::Annots(PDFDoc *docA, Object *annotsObj) { Annot *annot; Object obj1; Ref ref; int size; int i; doc = docA; annots = NULL; size = 0; nAnnots = 0; if (annotsObj->isArray()) { for (i = 0; i < annotsObj->arrayGetLength(); ++i) { if (annotsObj->arrayGetNF(i, &obj1)->isRef()) { ref = obj1.getRef(); obj1.free(); annotsObj->arrayGet(i, &obj1); } else { ref.num = ref.gen = -1; } if (obj1.isDict()) { annot = new Annot(doc, obj1.getDict(), &ref); if (annot->isOk()) { if (nAnnots >= size) { size += 16; annots = (Annot **)greallocn(annots, size, sizeof(Annot *)); } annots[nAnnots++] = annot; } else { delete annot; } } obj1.free(); } } } Annots::~Annots() { int i; for (i = 0; i < nAnnots; ++i) { delete annots[i]; } gfree(annots); } void Annots::generateAppearances() { Dict *acroForm; Object obj1, obj2; Ref ref; int i; acroForm = doc->getCatalog()->getAcroForm()->isDict() ? doc->getCatalog()->getAcroForm()->getDict() : NULL; if (acroForm->lookup("Fields", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGetNF(i, &obj2)->isRef()) { ref = obj2.getRef(); obj2.free(); obj1.arrayGet(i, &obj2); } else { ref.num = ref.gen = -1; } if (obj2.isDict()) { scanFieldAppearances(obj2.getDict(), &ref, NULL, acroForm); } obj2.free(); } } obj1.free(); } void Annots::scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, Dict *acroForm) { Annot *annot; Object obj1, obj2; Ref ref2; int i; // non-terminal node: scan the children if (node->lookup("Kids", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGetNF(i, &obj2)->isRef()) { ref2 = obj2.getRef(); obj2.free(); obj1.arrayGet(i, &obj2); } else { ref2.num = ref2.gen = -1; } if (obj2.isDict()) { scanFieldAppearances(obj2.getDict(), &ref2, node, acroForm); } obj2.free(); } obj1.free(); return; } obj1.free(); // terminal node: this is either a combined annot/field dict, or an // annot dict whose parent is a field if ((annot = findAnnot(ref))) { node->lookupNF("Parent", &obj1); if (!parent || !obj1.isNull()) { annot->generateFieldAppearance(node, node, acroForm); } else { annot->generateFieldAppearance(parent, node, acroForm); } obj1.free(); } } Annot *Annots::findAnnot(Ref *ref) { int i; for (i = 0; i < nAnnots; ++i) { if (annots[i]->match(ref)) { return annots[i]; } } return NULL; } xpdf-3.03/xpdf/Makefile.dep0000644000076400007640000000000011622305345015051 0ustar derekndereknxpdf-3.03/xpdf/vms_make.com0000644000076400007640000000735311622305345015166 0ustar dereknderekn$!======================================================================== $! $! Xpdf compile script for VMS. $! $! Written by Patrick Moreau, Martin P.J. Zinser. $! $! Copyright 1996-2003 Glyph & Cog, LLC $! $!======================================================================== $! $ i = 0 $ j = 0 $ APPS = "XPDF,PDFTOPS,PDFTOTEXT,PDFINFO,PDFTOPBM,PDFIMAGES,PDFFONTS" $ if f$search("COMMON.OLB").eqs."" then lib/create common.olb $! $ COMMON_OBJS = "Annot.obj,Array.obj,BuiltinFont.obj," + - "BuiltinFontTables.obj,Catalog.obj,CharCodeToUnicode.obj," + - "CMap.obj,Decrypt.obj,Dict.obj,Error.obj," + - "FontEncodingTables.obj,FontFile.obj," + - "Function.obj,Gfx.obj,GfxFont.obj,GfxState.obj,"+ - "GlobalParams.obj,JArithmeticDecoder.obj,JBIG2Stream.obj,"+ - "Lexer.obj,Link.obj,NameToCharCode.obj,Object.obj,"+ - "Outline.obj,OutputDev.obj,Page.obj,Parser.obj,PDFdoc.obj," + - "PDFDocEncoding.obj,PSTokenizer.obj,Stream.obj," + - "UnicodeMap.obj,UnicodeTypeTable.obj,XRef.obj" $ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib" $! $ XPDF_OBJS = "xpdf.obj,FTFont.obj,PSOutputDev.obj," + - "SFont.obj,T1Font.obj,TextOutputDev.obj,TTFont.obj," + - "XOutputDev.obj,XPDFApp.obj,XPDFCore.obj,XPDFTree.obj," + - "XPDFViewer.obj,XPixmapOutputDev.obj" $ XPDF_LIBS = "" $! $ PDFTOPS_OBJS = "pdftops.obj,PSOutputDev.obj" $ PDFTOPS_LIBS = "" $! $ PDFTOTEXT_OBJS = "pdftotext.obj,TextOutputDev.obj" $ PDFTOTEXT_LIBS = "" $! $ PDFINFO_OBJS = "pdfinfo.obj" $ PDFINFO_LIBS = "" $! $ PDFTOPBM_OBJS = "pdftopbm.obj,FTFont.obj,PBMOutputDev.obj,SFont.obj," + - "T1Font.obj,TextOutputDev.obj,TTFont.obj,XOutputDev.obj" $ PDFTOPBM_LIBS = "" $! $ PDFIMAGES_OBJS = "pdfimages.obj,ImageOutputDev.obj" $ PDFIMAGES_LIBS = "" $! $ PDFFONTS_OBJS = "pdffonts.obj" $ PDFFONTS_LIBS = "" $! $COMPILE_CXX_LOOP: $ file = f$element(i, ",",COMMON_OBJS) $ if file .eqs. "," then goto BUILD_APPS $ i = i + 1 $ name = f$parse(file,,,"NAME") $ call make 'file "CXXCOMP ''name'.cc" - 'name'.cc $ call make common.olb "lib/replace common.olb ''name'.obj" - 'name'.obj $ goto COMPILE_CXX_LOOP $! $BUILD_APPS: $ curr_app = f$element(j,",",APPS) $ if curr_app .eqs. "," then exit $ j = j + 1 $ i = 0 $COMPILE_APP: $ file = f$element(i,",",'curr_app'_OBJS) $ if file .eqs. "," then goto LINK_APP $ i = i + 1 $ name = f$parse(file,,,"NAME") $ call make 'file "CXXCOMP ''name'.cc" - 'name'.cc $ goto COMPILE_APP $LINK_APP: $ if 'curr_app'_LIBS .nes. "" $ then $ LIBS = 'curr_app'_LIBS + "," + COMMON_LIBS $ else $ LIBS = COMMON_LIBS $ endif $ OBJS = 'curr_app'_OBJS $ write sys$output "Linking ''curr_app'..." $ xpdf_link/exe='curr_app'.exe 'OBJS','libs',[-]xpdf.opt/opt $! $ goto BUILD_APPS $ exit $! $MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES $ V = 'F$Verify(0) $! P1 = What we are trying to make $! P2 = Command to make it $! P3 - P8 What it depends on $ $ If F$Search(P1) .Eqs. "" Then Goto Makeit $ Time = F$CvTime(F$File(P1,"RDT")) $arg=3 $Loop: $ Argument = P'arg $ If Argument .Eqs. "" Then Goto Exit $ El=0 $Loop2: $ File = F$Element(El," ",Argument) $ If File .Eqs. " " Then Goto Endl $ AFile = "" $Loop3: $ OFile = AFile $ AFile = F$Search(File) $ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl $ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit $ Goto Loop3 $NextEL: $ El = El + 1 $ Goto Loop2 $EndL: $ arg=arg+1 $ If arg .Le. 8 Then Goto Loop $ Goto Exit $ $Makeit: $ VV=F$VERIFY(0) $ write sys$output P2 $ 'P2 $ VV='F$Verify(VV) $Exit: $ If V Then Set Verify $ENDSUBROUTINE xpdf-3.03/xpdf/Decrypt.cc0000644000076400007640000010053411622305345014600 0ustar dereknderekn//======================================================================== // // Decrypt.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "Decrypt.h" static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen); static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen); static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last); static void sha256(Guchar *msg, int msgLen, Guchar *hash); 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 //------------------------------------------------------------------------ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, GString *ownerEnc, GString *userEnc, int permissions, GString *fileID, GString *ownerPassword, GString *userPassword, Guchar *fileKey, GBool encryptMetadata, GBool *ownerPasswordOk) { DecryptAES256State state; Guchar test[127 + 56], test2[32]; GString *userPassword2; Guchar fState[256]; Guchar tmpKey[16]; Guchar fx, fy; int len, i, j; *ownerPasswordOk = gFalse; if (encRevision == 5) { // check the owner password if (ownerPassword) { //~ this is supposed to convert the password to UTF-8 using "SASLprep" len = ownerPassword->getLength(); if (len > 127) { len = 127; } memcpy(test, ownerPassword->getCString(), len); memcpy(test + len, ownerKey->getCString() + 32, 8); memcpy(test + len + 8, userKey->getCString(), 48); sha256(test, len + 56, test); if (!memcmp(test, ownerKey->getCString(), 32)) { // compute the file key from the owner password memcpy(test, ownerPassword->getCString(), len); memcpy(test + len, ownerKey->getCString() + 40, 8); memcpy(test + len + 8, userKey->getCString(), 48); sha256(test, len + 56, test); aes256KeyExpansion(&state, test, 32); for (i = 0; i < 16; ++i) { state.cbc[i] = 0; } aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString(), gFalse); memcpy(fileKey, state.buf, 16); aes256DecryptBlock(&state, (Guchar *)ownerEnc->getCString() + 16, gFalse); memcpy(fileKey + 16, state.buf, 16); *ownerPasswordOk = gTrue; return gTrue; } } // check the user password if (userPassword) { //~ this is supposed to convert the password to UTF-8 using "SASLprep" len = userPassword->getLength(); if (len > 127) { len = 127; } memcpy(test, userPassword->getCString(), len); memcpy(test + len, userKey->getCString() + 32, 8); sha256(test, len + 8, test); if (!memcmp(test, userKey->getCString(), 32)) { // compute the file key from the user password memcpy(test, userPassword->getCString(), len); memcpy(test + len, userKey->getCString() + 40, 8); sha256(test, len + 8, test); aes256KeyExpansion(&state, test, 32); for (i = 0; i < 16; ++i) { state.cbc[i] = 0; } aes256DecryptBlock(&state, (Guchar *)userEnc->getCString(), gFalse); memcpy(fileKey, state.buf, 16); aes256DecryptBlock(&state, (Guchar *)userEnc->getCString() + 16, gFalse); memcpy(fileKey + 16, state.buf, 16); return gTrue; } } return gFalse; } else { // try using the supplied owner password to generate the user password if (ownerPassword) { len = ownerPassword->getLength(); if (len < 32) { memcpy(test, ownerPassword->getCString(), len); memcpy(test + len, passwordPad, 32 - len); } else { memcpy(test, ownerPassword->getCString(), 32); } md5(test, 32, test); if (encRevision == 3) { for (i = 0; i < 50; ++i) { md5(test, keyLength, test); } } if (encRevision == 2) { rc4InitKey(test, keyLength, fState); fx = fy = 0; for (i = 0; i < 32; ++i) { test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i)); } } else { memcpy(test2, ownerKey->getCString(), 32); for (i = 19; i >= 0; --i) { for (j = 0; j < keyLength; ++j) { tmpKey[j] = test[j] ^ i; } rc4InitKey(tmpKey, keyLength, fState); fx = fy = 0; for (j = 0; j < 32; ++j) { test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]); } } } userPassword2 = new GString((char *)test2, 32); if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, permissions, fileID, userPassword2, fileKey, encryptMetadata)) { *ownerPasswordOk = gTrue; delete userPassword2; return gTrue; } delete userPassword2; } // try using the supplied user password return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey, permissions, fileID, userPassword, fileKey, encryptMetadata); } } GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, GString *userPassword, Guchar *fileKey, GBool encryptMetadata) { Guchar *buf; Guchar test[32]; Guchar fState[256]; Guchar tmpKey[16]; Guchar fx, fy; int len, i, j; GBool ok; // generate file key buf = (Guchar *)gmalloc(72 + fileID->getLength()); if (userPassword) { len = userPassword->getLength(); if (len < 32) { memcpy(buf, userPassword->getCString(), len); memcpy(buf + len, passwordPad, 32 - len); } else { memcpy(buf, userPassword->getCString(), 32); } } else { memcpy(buf, passwordPad, 32); } memcpy(buf + 32, ownerKey->getCString(), 32); buf[64] = permissions & 0xff; buf[65] = (permissions >> 8) & 0xff; buf[66] = (permissions >> 16) & 0xff; buf[67] = (permissions >> 24) & 0xff; memcpy(buf + 68, fileID->getCString(), fileID->getLength()); len = 68 + fileID->getLength(); if (!encryptMetadata) { buf[len++] = 0xff; buf[len++] = 0xff; buf[len++] = 0xff; buf[len++] = 0xff; } md5(buf, len, fileKey); if (encRevision == 3) { for (i = 0; i < 50; ++i) { md5(fileKey, keyLength, fileKey); } } // test user password if (encRevision == 2) { rc4InitKey(fileKey, keyLength, fState); fx = fy = 0; for (i = 0; i < 32; ++i) { test[i] = rc4DecryptByte(fState, &fx, &fy, userKey->getChar(i)); } ok = memcmp(test, passwordPad, 32) == 0; } else if (encRevision == 3) { memcpy(test, userKey->getCString(), 32); for (i = 19; i >= 0; --i) { for (j = 0; j < keyLength; ++j) { tmpKey[j] = fileKey[j] ^ i; } rc4InitKey(tmpKey, keyLength, fState); fx = fy = 0; for (j = 0; j < 32; ++j) { test[j] = rc4DecryptByte(fState, &fx, &fy, test[j]); } } memcpy(buf, passwordPad, 32); memcpy(buf + 32, fileID->getCString(), fileID->getLength()); md5(buf, 32 + fileID->getLength(), buf); ok = memcmp(test, buf, 16) == 0; } else { ok = gFalse; } gfree(buf); return ok; } //------------------------------------------------------------------------ // DecryptStream //------------------------------------------------------------------------ DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, CryptAlgorithm algoA, int keyLength, int objNum, int objGen): FilterStream(strA) { int i; algo = algoA; // construct object key for (i = 0; i < keyLength; ++i) { objKey[i] = fileKey[i]; } switch (algo) { case cryptRC4: objKey[keyLength] = objNum & 0xff; objKey[keyLength + 1] = (objNum >> 8) & 0xff; objKey[keyLength + 2] = (objNum >> 16) & 0xff; objKey[keyLength + 3] = objGen & 0xff; objKey[keyLength + 4] = (objGen >> 8) & 0xff; md5(objKey, keyLength + 5, objKey); if ((objKeyLength = keyLength + 5) > 16) { objKeyLength = 16; } break; case cryptAES: objKey[keyLength] = objNum & 0xff; objKey[keyLength + 1] = (objNum >> 8) & 0xff; objKey[keyLength + 2] = (objNum >> 16) & 0xff; objKey[keyLength + 3] = objGen & 0xff; objKey[keyLength + 4] = (objGen >> 8) & 0xff; objKey[keyLength + 5] = 0x73; // 's' objKey[keyLength + 6] = 0x41; // 'A' objKey[keyLength + 7] = 0x6c; // 'l' objKey[keyLength + 8] = 0x54; // 'T' md5(objKey, keyLength + 9, objKey); if ((objKeyLength = keyLength + 5) > 16) { objKeyLength = 16; } break; case cryptAES256: objKeyLength = keyLength; break; } } DecryptStream::~DecryptStream() { delete str; } void DecryptStream::reset() { int i; str->reset(); switch (algo) { case cryptRC4: state.rc4.x = state.rc4.y = 0; rc4InitKey(objKey, objKeyLength, state.rc4.state); state.rc4.buf = EOF; break; case cryptAES: aesKeyExpansion(&state.aes, objKey, objKeyLength); for (i = 0; i < 16; ++i) { state.aes.cbc[i] = str->getChar(); } state.aes.bufIdx = 16; break; case cryptAES256: aes256KeyExpansion(&state.aes256, objKey, objKeyLength); for (i = 0; i < 16; ++i) { state.aes256.cbc[i] = str->getChar(); } state.aes256.bufIdx = 16; break; } } int DecryptStream::getChar() { Guchar in[16]; int c, i; c = EOF; // make gcc happy switch (algo) { case cryptRC4: if (state.rc4.buf == EOF) { c = str->getChar(); if (c != EOF) { state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); } } c = state.rc4.buf; state.rc4.buf = EOF; break; case cryptAES: if (state.aes.bufIdx == 16) { for (i = 0; i < 16; ++i) { if ((c = str->getChar()) == EOF) { return EOF; } in[i] = (Guchar)c; } aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); } if (state.aes.bufIdx == 16) { c = EOF; } else { c = state.aes.buf[state.aes.bufIdx++]; } break; case cryptAES256: if (state.aes256.bufIdx == 16) { for (i = 0; i < 16; ++i) { if ((c = str->getChar()) == EOF) { return EOF; } in[i] = (Guchar)c; } aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); } if (state.aes256.bufIdx == 16) { c = EOF; } else { c = state.aes256.buf[state.aes256.bufIdx++]; } break; } return c; } int DecryptStream::lookChar() { Guchar in[16]; int c, i; c = EOF; // make gcc happy switch (algo) { case cryptRC4: if (state.rc4.buf == EOF) { c = str->getChar(); if (c != EOF) { state.rc4.buf = rc4DecryptByte(state.rc4.state, &state.rc4.x, &state.rc4.y, (Guchar)c); } } c = state.rc4.buf; break; case cryptAES: if (state.aes.bufIdx == 16) { for (i = 0; i < 16; ++i) { if ((c = str->getChar()) == EOF) { return EOF; } in[i] = c; } aesDecryptBlock(&state.aes, in, str->lookChar() == EOF); } if (state.aes.bufIdx == 16) { c = EOF; } else { c = state.aes.buf[state.aes.bufIdx]; } break; case cryptAES256: if (state.aes256.bufIdx == 16) { for (i = 0; i < 16; ++i) { if ((c = str->getChar()) == EOF) { return EOF; } in[i] = c; } aes256DecryptBlock(&state.aes256, in, str->lookChar() == EOF); } if (state.aes256.bufIdx == 16) { c = EOF; } else { c = state.aes256.buf[state.aes256.bufIdx]; } break; } return c; } GBool DecryptStream::isBinary(GBool last) { return str->isBinary(last); } //------------------------------------------------------------------------ // RC4-compatible decryption //------------------------------------------------------------------------ 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; } } 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]; } //------------------------------------------------------------------------ // AES decryption //------------------------------------------------------------------------ static Guchar sbox[256] = { 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; static Guchar invSbox[256] = { 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; static Guint rcon[11] = { 0x00000000, // unused 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000 }; static inline Guint subWord(Guint x) { return (sbox[x >> 24] << 24) | (sbox[(x >> 16) & 0xff] << 16) | (sbox[(x >> 8) & 0xff] << 8) | sbox[x & 0xff]; } static inline Guint rotWord(Guint x) { return ((x << 8) & 0xffffffff) | (x >> 24); } static inline void invSubBytes(Guchar *state) { int i; for (i = 0; i < 16; ++i) { state[i] = invSbox[state[i]]; } } static inline void invShiftRows(Guchar *state) { Guchar t; t = state[7]; state[7] = state[6]; state[6] = state[5]; state[5] = state[4]; state[4] = t; t = state[8]; state[8] = state[10]; state[10] = t; t = state[9]; state[9] = state[11]; state[11] = t; t = state[12]; state[12] = state[13]; state[13] = state[14]; state[14] = state[15]; state[15] = t; } // {09} \cdot s static inline Guchar mul09(Guchar s) { Guchar s2, s4, s8; s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); return s ^ s8; } // {0b} \cdot s static inline Guchar mul0b(Guchar s) { Guchar s2, s4, s8; s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); return s ^ s2 ^ s8; } // {0d} \cdot s static inline Guchar mul0d(Guchar s) { Guchar s2, s4, s8; s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); return s ^ s4 ^ s8; } // {0e} \cdot s static inline Guchar mul0e(Guchar s) { Guchar s2, s4, s8; s2 = (s & 0x80) ? ((s << 1) ^ 0x1b) : (s << 1); s4 = (s2 & 0x80) ? ((s2 << 1) ^ 0x1b) : (s2 << 1); s8 = (s4 & 0x80) ? ((s4 << 1) ^ 0x1b) : (s4 << 1); return s2 ^ s4 ^ s8; } static inline void invMixColumns(Guchar *state) { int c; Guchar s0, s1, s2, s3; for (c = 0; c < 4; ++c) { s0 = state[c]; s1 = state[4+c]; s2 = state[8+c]; s3 = state[12+c]; state[c] = mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3); state[4+c] = mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3); state[8+c] = mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3); state[12+c] = mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3); } } static inline void invMixColumnsW(Guint *w) { int c; Guchar s0, s1, s2, s3; for (c = 0; c < 4; ++c) { s0 = w[c] >> 24; s1 = w[c] >> 16; s2 = w[c] >> 8; s3 = w[c]; w[c] = ((mul0e(s0) ^ mul0b(s1) ^ mul0d(s2) ^ mul09(s3)) << 24) | ((mul09(s0) ^ mul0e(s1) ^ mul0b(s2) ^ mul0d(s3)) << 16) | ((mul0d(s0) ^ mul09(s1) ^ mul0e(s2) ^ mul0b(s3)) << 8) | (mul0b(s0) ^ mul0d(s1) ^ mul09(s2) ^ mul0e(s3)); } } static inline void addRoundKey(Guchar *state, Guint *w) { int c; for (c = 0; c < 4; ++c) { state[c] ^= w[c] >> 24; state[4+c] ^= w[c] >> 16; state[8+c] ^= w[c] >> 8; state[12+c] ^= w[c]; } } static void aesKeyExpansion(DecryptAESState *s, Guchar *objKey, int objKeyLen) { Guint temp; int i, round; //~ this assumes objKeyLen == 16 for (i = 0; i < 4; ++i) { s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) + (objKey[4*i+2] << 8) + objKey[4*i+3]; } for (i = 4; i < 44; ++i) { temp = s->w[i-1]; if (!(i & 3)) { temp = subWord(rotWord(temp)) ^ rcon[i/4]; } s->w[i] = s->w[i-4] ^ temp; } for (round = 1; round <= 9; ++round) { invMixColumnsW(&s->w[round * 4]); } } static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last) { int c, round, n, i; // initial state for (c = 0; c < 4; ++c) { s->state[c] = in[4*c]; s->state[4+c] = in[4*c+1]; s->state[8+c] = in[4*c+2]; s->state[12+c] = in[4*c+3]; } // round 0 addRoundKey(s->state, &s->w[10 * 4]); // rounds 1-9 for (round = 9; round >= 1; --round) { invSubBytes(s->state); invShiftRows(s->state); invMixColumns(s->state); addRoundKey(s->state, &s->w[round * 4]); } // round 10 invSubBytes(s->state); invShiftRows(s->state); addRoundKey(s->state, &s->w[0]); // CBC for (c = 0; c < 4; ++c) { s->buf[4*c] = s->state[c] ^ s->cbc[4*c]; s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1]; s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2]; s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3]; } // save the input block for the next CBC for (i = 0; i < 16; ++i) { s->cbc[i] = in[i]; } // remove padding s->bufIdx = 0; if (last) { n = s->buf[15]; if (n < 1 || n > 16) { // this should never happen n = 16; } for (i = 15; i >= n; --i) { s->buf[i] = s->buf[i-n]; } s->bufIdx = n; } } //------------------------------------------------------------------------ // AES-256 decryption //------------------------------------------------------------------------ static void aes256KeyExpansion(DecryptAES256State *s, Guchar *objKey, int objKeyLen) { Guint temp; int i, round; //~ this assumes objKeyLen == 32 for (i = 0; i < 8; ++i) { s->w[i] = (objKey[4*i] << 24) + (objKey[4*i+1] << 16) + (objKey[4*i+2] << 8) + objKey[4*i+3]; } for (i = 8; i < 60; ++i) { temp = s->w[i-1]; if ((i & 7) == 0) { temp = subWord(rotWord(temp)) ^ rcon[i/8]; } else if ((i & 7) == 4) { temp = subWord(temp); } s->w[i] = s->w[i-8] ^ temp; } for (round = 1; round <= 13; ++round) { invMixColumnsW(&s->w[round * 4]); } } static void aes256DecryptBlock(DecryptAES256State *s, Guchar *in, GBool last) { int c, round, n, i; // initial state for (c = 0; c < 4; ++c) { s->state[c] = in[4*c]; s->state[4+c] = in[4*c+1]; s->state[8+c] = in[4*c+2]; s->state[12+c] = in[4*c+3]; } // round 0 addRoundKey(s->state, &s->w[14 * 4]); // rounds 13-1 for (round = 13; round >= 1; --round) { invSubBytes(s->state); invShiftRows(s->state); invMixColumns(s->state); addRoundKey(s->state, &s->w[round * 4]); } // round 14 invSubBytes(s->state); invShiftRows(s->state); addRoundKey(s->state, &s->w[0]); // CBC for (c = 0; c < 4; ++c) { s->buf[4*c] = s->state[c] ^ s->cbc[4*c]; s->buf[4*c+1] = s->state[4+c] ^ s->cbc[4*c+1]; s->buf[4*c+2] = s->state[8+c] ^ s->cbc[4*c+2]; s->buf[4*c+3] = s->state[12+c] ^ s->cbc[4*c+3]; } // save the input block for the next CBC for (i = 0; i < 16; ++i) { s->cbc[i] = in[i]; } // remove padding s->bufIdx = 0; if (last) { n = s->buf[15]; if (n < 1 || n > 16) { // this should never happen n = 16; } for (i = 15; i >= n; --i) { s->buf[i] = s->buf[i-n]; } s->bufIdx = n; } } //------------------------------------------------------------------------ // MD5 message digest //------------------------------------------------------------------------ // this works around a bug in older Sun compilers 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); } 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; // sanity check if (msgLen < 0) { return; } // 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] = (Guchar)(a & 0xff); digest[1] = (Guchar)((a >>= 8) & 0xff); digest[2] = (Guchar)((a >>= 8) & 0xff); digest[3] = (Guchar)((a >>= 8) & 0xff); digest[4] = (Guchar)(b & 0xff); digest[5] = (Guchar)((b >>= 8) & 0xff); digest[6] = (Guchar)((b >>= 8) & 0xff); digest[7] = (Guchar)((b >>= 8) & 0xff); digest[8] = (Guchar)(c & 0xff); digest[9] = (Guchar)((c >>= 8) & 0xff); digest[10] = (Guchar)((c >>= 8) & 0xff); digest[11] = (Guchar)((c >>= 8) & 0xff); digest[12] = (Guchar)(d & 0xff); digest[13] = (Guchar)((d >>= 8) & 0xff); digest[14] = (Guchar)((d >>= 8) & 0xff); digest[15] = (Guchar)((d >>= 8) & 0xff); } //------------------------------------------------------------------------ // SHA-256 hash //------------------------------------------------------------------------ static Guint sha256K[64] = { 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; static inline Guint rotr(Guint x, Guint n) { return (x >> n) | (x << (32 - n)); } static inline Guint sha256Ch(Guint x, Guint y, Guint z) { return (x & y) ^ (~x & z); } static inline Guint sha256Maj(Guint x, Guint y, Guint z) { return (x & y) ^ (x & z) ^ (y & z); } static inline Guint sha256Sigma0(Guint x) { return rotr(x, 2) ^ rotr(x, 13) ^ rotr(x, 22); } static inline Guint sha256Sigma1(Guint x) { return rotr(x, 6) ^ rotr(x, 11) ^ rotr(x, 25); } static inline Guint sha256sigma0(Guint x) { return rotr(x, 7) ^ rotr(x, 18) ^ (x >> 3); } static inline Guint sha256sigma1(Guint x) { return rotr(x, 17) ^ rotr(x, 19) ^ (x >> 10); } void sha256HashBlock(Guchar *blk, Guint *H) { Guint W[64]; Guint a, b, c, d, e, f, g, h; Guint T1, T2; Guint t; // 1. prepare the message schedule for (t = 0; t < 16; ++t) { W[t] = (blk[t*4] << 24) | (blk[t*4 + 1] << 16) | (blk[t*4 + 2] << 8) | blk[t*4 + 3]; } for (t = 16; t < 64; ++t) { W[t] = sha256sigma1(W[t-2]) + W[t-7] + sha256sigma0(W[t-15]) + W[t-16]; } // 2. initialize the eight working variables a = H[0]; b = H[1]; c = H[2]; d = H[3]; e = H[4]; f = H[5]; g = H[6]; h = H[7]; // 3. for (t = 0; t < 64; ++t) { T1 = h + sha256Sigma1(e) + sha256Ch(e,f,g) + sha256K[t] + W[t]; T2 = sha256Sigma0(a) + sha256Maj(a,b,c); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2; } // 4. compute the intermediate hash value H[0] += a; H[1] += b; H[2] += c; H[3] += d; H[4] += e; H[5] += f; H[6] += g; H[7] += h; } static void sha256(Guchar *msg, int msgLen, Guchar *hash) { Guchar blk[64]; Guint H[8]; int blkLen, i; H[0] = 0x6a09e667; H[1] = 0xbb67ae85; H[2] = 0x3c6ef372; H[3] = 0xa54ff53a; H[4] = 0x510e527f; H[5] = 0x9b05688c; H[6] = 0x1f83d9ab; H[7] = 0x5be0cd19; blkLen = 0; for (i = 0; i + 64 <= msgLen; i += 64) { sha256HashBlock(msg + i, H); } blkLen = msgLen - i; if (blkLen > 0) { memcpy(blk, msg + i, blkLen); } // pad the message blk[blkLen++] = 0x80; if (blkLen > 56) { while (blkLen < 64) { blk[blkLen++] = 0; } sha256HashBlock(blk, H); blkLen = 0; } while (blkLen < 56) { blk[blkLen++] = 0; } blk[56] = 0; blk[57] = 0; blk[58] = 0; blk[59] = 0; blk[60] = (Guchar)(msgLen >> 21); blk[61] = (Guchar)(msgLen >> 13); blk[62] = (Guchar)(msgLen >> 5); blk[63] = (Guchar)(msgLen << 3); sha256HashBlock(blk, H); // copy the output into the buffer (convert words to bytes) for (i = 0; i < 8; ++i) { hash[i*4] = (Guchar)(H[i] >> 24); hash[i*4 + 1] = (Guchar)(H[i] >> 16); hash[i*4 + 2] = (Guchar)(H[i] >> 8); hash[i*4 + 3] = (Guchar)H[i]; } } xpdf-3.03/xpdf/Catalog.h0000644000076400007640000000636311622305345014407 0ustar dereknderekn//======================================================================== // // Catalog.h // // Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== #ifndef CATALOG_H #define CATALOG_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "CharTypes.h" class GList; class PDFDoc; class XRef; class Object; class Page; class PageAttrs; struct Ref; class LinkDest; class PageTreeNode; //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ class Catalog { public: // Constructor. Catalog(PDFDoc *docA); // Destructor. ~Catalog(); // Is catalog valid? GBool isOk() { return ok; } // Get number of pages. int getNumPages() { return numPages; } // Get a page. Page *getPage(int i); // Get the reference for a page object. Ref *getPageRef(int i); // Remove a page from the catalog. (It can be reloaded later by // calling getPage). void doneWithPage(int i); // Return base URI, or NULL if none. GString *getBaseURI() { return baseURI; } // Return the contents of the metadata stream, or NULL if there is // no metadata. GString *readMetadata(); // Return the structure tree root object. Object *getStructTreeRoot() { return &structTreeRoot; } // Find a page, given its object ID. Returns page number, or 0 if // not found. int findPage(int num, int gen); // Find a named destination. Returns the link destination, or // NULL if is not a destination. LinkDest *findDest(GString *name); Object *getDests() { return &dests; } Object *getNameTree() { return &nameTree; } Object *getOutline() { return &outline; } Object *getAcroForm() { return &acroForm; } Object *getOCProperties() { return &ocProperties; } // Get the list of embedded files. int getNumEmbeddedFiles(); Unicode *getEmbeddedFileName(int idx); int getEmbeddedFileNameLength(int idx); Object *getEmbeddedFileStreamObj(int idx, Object *strObj); private: PDFDoc *doc; XRef *xref; // the xref table for this PDF file PageTreeNode *pageTree; // the page tree Page **pages; // array of pages Ref *pageRefs; // object ID for each page int numPages; // number of pages int pagesSize; // size of pages array Object dests; // named destination dictionary Object nameTree; // name tree GString *baseURI; // base URI for URI-type links Object metadata; // metadata stream Object structTreeRoot; // structure tree root dictionary Object outline; // outline dictionary Object acroForm; // AcroForm dictionary Object ocProperties; // OCProperties dictionary GList *embeddedFiles; // embedded file list [EmbeddedFile] GBool ok; // true if catalog is valid Object *findDestInTree(Object *tree, GString *name, Object *obj); GBool readPageTree(Object *catDict); int countPageTree(Object *pagesObj); void loadPage(int pg); void loadPage2(int pg, int relPg, PageTreeNode *node); void readEmbeddedFileList(Dict *catDict); void readEmbeddedFileTree(Object *node); void readFileAttachmentAnnots(Object *pageNodeRef, char *touchedObjs); void readEmbeddedFile(Object *fileSpec, Object *name1); }; #endif xpdf-3.03/xpdf/Page.h0000644000076400007640000001367111622305345013711 0ustar dereknderekn//======================================================================== // // Page.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PAGE_H #define PAGE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" class Dict; class PDFDoc; class XRef; class OutputDev; class Links; //------------------------------------------------------------------------ class PDFRectangle { public: double x1, y1, x2, y2; PDFRectangle() { x1 = y1 = x2 = y2 = 0; } PDFRectangle(double x1A, double y1A, double x2A, double y2A) { x1 = x1A; y1 = y1A; x2 = x2A; y2 = y2A; } GBool isValid() { return x1 != 0 || y1 != 0 || x2 != 0 || y2 != 0; } void clipTo(PDFRectangle *rect); }; //------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ class PageAttrs { public: // Construct a new PageAttrs object by merging a dictionary // (of type Pages or Page) into another PageAttrs object. If // is NULL, uses defaults. PageAttrs(PageAttrs *attrs, Dict *dict); // Construct a new PageAttrs object for an empty page (only used // when there is an error in the page tree). PageAttrs(); // Destructor. ~PageAttrs(); // Accessors. PDFRectangle *getMediaBox() { return &mediaBox; } PDFRectangle *getCropBox() { return &cropBox; } GBool isCropped() { return haveCropBox; } PDFRectangle *getBleedBox() { return &bleedBox; } PDFRectangle *getTrimBox() { return &trimBox; } PDFRectangle *getArtBox() { return &artBox; } int getRotate() { return rotate; } GString *getLastModified() { return lastModified.isString() ? lastModified.getString() : (GString *)NULL; } Dict *getBoxColorInfo() { return boxColorInfo.isDict() ? boxColorInfo.getDict() : (Dict *)NULL; } Dict *getGroup() { return group.isDict() ? group.getDict() : (Dict *)NULL; } Stream *getMetadata() { return metadata.isStream() ? metadata.getStream() : (Stream *)NULL; } Dict *getPieceInfo() { return pieceInfo.isDict() ? pieceInfo.getDict() : (Dict *)NULL; } Dict *getSeparationInfo() { return separationInfo.isDict() ? separationInfo.getDict() : (Dict *)NULL; } Dict *getResourceDict() { return resources.isDict() ? resources.getDict() : (Dict *)NULL; } // Clip all other boxes to the MediaBox. void clipBoxes(); private: GBool readBox(Dict *dict, const char *key, PDFRectangle *box); PDFRectangle mediaBox; PDFRectangle cropBox; GBool haveCropBox; PDFRectangle bleedBox; PDFRectangle trimBox; PDFRectangle artBox; int rotate; Object lastModified; Object boxColorInfo; Object group; Object metadata; Object pieceInfo; Object separationInfo; Object resources; }; //------------------------------------------------------------------------ // Page //------------------------------------------------------------------------ class Page { public: // Constructor. Page(PDFDoc *docA, int numA, Dict *pageDict, PageAttrs *attrsA); // Create an empty page (only used when there is an error in the // page tree). Page(PDFDoc *docA, int numA); // Destructor. ~Page(); // Is page valid? GBool isOk() { return ok; } // Get page parameters. int getNum() { return num; } PDFRectangle *getMediaBox() { return attrs->getMediaBox(); } PDFRectangle *getCropBox() { return attrs->getCropBox(); } GBool isCropped() { return attrs->isCropped(); } double getMediaWidth() { return attrs->getMediaBox()->x2 - attrs->getMediaBox()->x1; } double getMediaHeight() { return attrs->getMediaBox()->y2 - attrs->getMediaBox()->y1; } double getCropWidth() { return attrs->getCropBox()->x2 - attrs->getCropBox()->x1; } double getCropHeight() { return attrs->getCropBox()->y2 - attrs->getCropBox()->y1; } PDFRectangle *getBleedBox() { return attrs->getBleedBox(); } PDFRectangle *getTrimBox() { return attrs->getTrimBox(); } PDFRectangle *getArtBox() { return attrs->getArtBox(); } int getRotate() { return attrs->getRotate(); } GString *getLastModified() { return attrs->getLastModified(); } Dict *getBoxColorInfo() { return attrs->getBoxColorInfo(); } Dict *getGroup() { return attrs->getGroup(); } Stream *getMetadata() { return attrs->getMetadata(); } Dict *getPieceInfo() { return attrs->getPieceInfo(); } Dict *getSeparationInfo() { return attrs->getSeparationInfo(); } // Get resource dictionary. Dict *getResourceDict() { return attrs->getResourceDict(); } // Get annotations array. Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } // Return a list of links. Links *getLinks(); // Get contents. Object *getContents(Object *obj) { return contents.fetch(xref, obj); } // Display a page. void display(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display part of a page. void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); void makeBox(double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool upsideDown, double sliceX, double sliceY, double sliceW, double sliceH, PDFRectangle *box, GBool *crop); void processLinks(OutputDev *out); // Get the page's default CTM. void getDefaultCTM(double *ctm, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool upsideDown); private: PDFDoc *doc; XRef *xref; // the xref table for this PDF file int num; // page number PageAttrs *attrs; // page attributes Object annots; // annotations array Object contents; // page contents GBool ok; // true if page is valid }; #endif xpdf-3.03/xpdf/CharCodeToUnicode.h0000644000076400007640000000635511622305345016320 0ustar dereknderekn//======================================================================== // // CharCodeToUnicode.h // // Mapping from character codes to Unicode. // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CHARCODETOUNICODE_H #define CHARCODETOUNICODE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "CharTypes.h" #if MULTITHREADED #include "GMutex.h" #endif struct CharCodeToUnicodeString; //------------------------------------------------------------------------ class CharCodeToUnicode { public: // Create an identity mapping (Unicode = CharCode). static CharCodeToUnicode *makeIdentityMapping(); // Read the CID-to-Unicode mapping for from the file // specified by . Sets the initial reference count to 1. // Returns NULL on failure. static CharCodeToUnicode *parseCIDToUnicode(GString *fileName, GString *collection); // Create a Unicode-to-Unicode mapping from the file specified by // . Sets the initial reference count to 1. Returns NULL // on failure. static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName); // Create the CharCode-to-Unicode mapping for an 8-bit font. // is an array of 256 Unicode indexes. Sets the initial // reference count to 1. static CharCodeToUnicode *make8BitToUnicode(Unicode *toUnicode); // Parse a ToUnicode CMap for an 8- or 16-bit font. static CharCodeToUnicode *parseCMap(GString *buf, int nBits); // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into // . void mergeCMap(GString *buf, int nBits); ~CharCodeToUnicode(); void incRefCnt(); void decRefCnt(); // Return true if this mapping matches the specified . GBool match(GString *tagA); // Set the mapping for . void setMapping(CharCode c, Unicode *u, int len); // Map a CharCode to Unicode. int mapToUnicode(CharCode c, Unicode *u, int size); // Return the mapping's length, i.e., one more than the max char // code supported by the mapping. CharCode getLength() { return mapLen; } private: void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits); void addMapping(CharCode code, char *uStr, int n, int offset); CharCodeToUnicode(); CharCodeToUnicode(GString *tagA); CharCodeToUnicode(GString *tagA, Unicode *mapA, CharCode mapLenA, GBool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA, int sMapSizeA); GString *tag; Unicode *map; CharCode mapLen; CharCodeToUnicodeString *sMap; int sMapLen, sMapSize; int refCnt; #if MULTITHREADED GMutex mutex; #endif }; //------------------------------------------------------------------------ class CharCodeToUnicodeCache { public: CharCodeToUnicodeCache(int sizeA); ~CharCodeToUnicodeCache(); // Get the CharCodeToUnicode object for . Increments its // reference count; there will be one reference for the cache plus // one for the caller of this function. Returns NULL on failure. CharCodeToUnicode *getCharCodeToUnicode(GString *tag); // Insert into the cache, in the most-recently-used position. void add(CharCodeToUnicode *ctu); private: CharCodeToUnicode **cache; int size; }; #endif xpdf-3.03/xpdf/Link.cc0000644000076400007640000004414311622305345014066 0ustar dereknderekn//======================================================================== // // Link.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "GString.h" #include "Error.h" #include "Object.h" #include "Array.h" #include "Dict.h" #include "Link.h" //------------------------------------------------------------------------ // LinkAction //------------------------------------------------------------------------ LinkAction *LinkAction::parseDest(Object *obj) { LinkAction *action; action = new LinkGoTo(obj); if (!action->isOk()) { delete action; return NULL; } return action; } LinkAction *LinkAction::parseAction(Object *obj, GString *baseURI) { LinkAction *action; Object obj2, obj3, obj4; if (!obj->isDict()) { error(errSyntaxWarning, -1, "Bad annotation action"); return NULL; } obj->dictLookup("S", &obj2); // GoTo action if (obj2.isName("GoTo")) { obj->dictLookup("D", &obj3); action = new LinkGoTo(&obj3); obj3.free(); // GoToR action } else if (obj2.isName("GoToR")) { obj->dictLookup("F", &obj3); obj->dictLookup("D", &obj4); action = new LinkGoToR(&obj3, &obj4); obj3.free(); obj4.free(); // Launch action } else if (obj2.isName("Launch")) { action = new LinkLaunch(obj); // URI action } else if (obj2.isName("URI")) { obj->dictLookup("URI", &obj3); action = new LinkURI(&obj3, baseURI); obj3.free(); // Named action } else if (obj2.isName("Named")) { obj->dictLookup("N", &obj3); action = new LinkNamed(&obj3); obj3.free(); // Movie action } else if (obj2.isName("Movie")) { obj->dictLookupNF("Annot", &obj3); obj->dictLookup("T", &obj4); action = new LinkMovie(&obj3, &obj4); obj3.free(); obj4.free(); // unknown action } else if (obj2.isName()) { action = new LinkUnknown(obj2.getName()); // action is missing or wrong type } else { error(errSyntaxWarning, -1, "Bad annotation action"); action = NULL; } obj2.free(); if (action && !action->isOk()) { delete action; return NULL; } return action; } GString *LinkAction::getFileSpecName(Object *fileSpecObj) { GString *name; Object obj1; name = NULL; // string if (fileSpecObj->isString()) { name = fileSpecObj->getString()->copy(); // dictionary } else if (fileSpecObj->isDict()) { #ifdef WIN32 if (!fileSpecObj->dictLookup("DOS", &obj1)->isString()) { #else if (!fileSpecObj->dictLookup("Unix", &obj1)->isString()) { #endif obj1.free(); fileSpecObj->dictLookup("F", &obj1); } if (obj1.isString()) { name = obj1.getString()->copy(); } else { error(errSyntaxWarning, -1, "Illegal file spec in link"); } obj1.free(); // error } else { error(errSyntaxWarning, -1, "Illegal file spec in link"); } // system-dependent path manipulation if (name) { #ifdef WIN32 int i, j; // "//...." --> "\...." // "/x/...." --> "x:\...." // "/server/share/...." --> "\\server\share\...." // convert escaped slashes to slashes and unescaped slashes to backslashes i = 0; if (name->getChar(0) == '/') { if (name->getLength() >= 2 && name->getChar(1) == '/') { name->del(0); i = 0; } else if (name->getLength() >= 2 && ((name->getChar(1) >= 'a' && name->getChar(1) <= 'z') || (name->getChar(1) >= 'A' && name->getChar(1) <= 'Z')) && (name->getLength() == 2 || name->getChar(2) == '/')) { name->setChar(0, name->getChar(1)); name->setChar(1, ':'); i = 2; } else { for (j = 2; j < name->getLength(); ++j) { if (name->getChar(j-1) != '\\' && name->getChar(j) == '/') { break; } } if (j < name->getLength()) { name->setChar(0, '\\'); name->insert(0, '\\'); i = 2; } } } for (; i < name->getLength(); ++i) { if (name->getChar(i) == '/') { name->setChar(i, '\\'); } else if (name->getChar(i) == '\\' && i+1 < name->getLength() && name->getChar(i+1) == '/') { name->del(i); } } #else // no manipulation needed for Unix #endif } return name; } //------------------------------------------------------------------------ // LinkDest //------------------------------------------------------------------------ LinkDest::LinkDest(Array *a) { Object obj1, obj2; // initialize fields left = bottom = right = top = zoom = 0; ok = gFalse; // get page if (a->getLength() < 2) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); return; } a->getNF(0, &obj1); if (obj1.isInt()) { pageNum = obj1.getInt() + 1; pageIsRef = gFalse; } else if (obj1.isRef()) { pageRef.num = obj1.getRefNum(); pageRef.gen = obj1.getRefGen(); pageIsRef = gTrue; } else { error(errSyntaxWarning, -1, "Bad annotation destination"); goto err2; } obj1.free(); // get destination type a->get(1, &obj1); // XYZ link if (obj1.isName("XYZ")) { kind = destXYZ; if (a->getLength() < 3) { changeLeft = gFalse; } else { a->get(2, &obj2); if (obj2.isNull()) { changeLeft = gFalse; } else if (obj2.isNum()) { changeLeft = gTrue; left = obj2.getNum(); } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); goto err1; } obj2.free(); } if (a->getLength() < 4) { changeTop = gFalse; } else { a->get(3, &obj2); if (obj2.isNull()) { changeTop = gFalse; } else if (obj2.isNum()) { changeTop = gTrue; top = obj2.getNum(); } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); goto err1; } obj2.free(); } if (a->getLength() < 5) { changeZoom = gFalse; } else { a->get(4, &obj2); if (obj2.isNull()) { changeZoom = gFalse; } else if (obj2.isNum()) { changeZoom = gTrue; zoom = obj2.getNum(); } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); goto err1; } obj2.free(); } // Fit link } else if (obj1.isName("Fit")) { if (a->getLength() < 2) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFit; // FitH link } else if (obj1.isName("FitH")) { if (a->getLength() < 3) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitH; if (a->get(2, &obj2)->isNum()) { top = obj2.getNum(); changeTop = gTrue; } else if (obj2.isNull()) { changeTop = gFalse; } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } obj2.free(); // FitV link } else if (obj1.isName("FitV")) { if (a->getLength() < 3) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitV; if (a->get(2, &obj2)->isNum()) { left = obj2.getNum(); changeLeft = gTrue; } else if (obj2.isNull()) { changeLeft = gFalse; } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } obj2.free(); // FitR link } else if (obj1.isName("FitR")) { if (a->getLength() < 6) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitR; if (a->get(2, &obj2)->isNum()) { left = obj2.getNum(); } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } obj2.free(); if (!a->get(3, &obj2)->isNum()) { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } bottom = obj2.getNum(); obj2.free(); if (!a->get(4, &obj2)->isNum()) { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } right = obj2.getNum(); obj2.free(); if (!a->get(5, &obj2)->isNum()) { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } top = obj2.getNum(); obj2.free(); // FitB link } else if (obj1.isName("FitB")) { if (a->getLength() < 2) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitB; // FitBH link } else if (obj1.isName("FitBH")) { if (a->getLength() < 3) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitBH; if (a->get(2, &obj2)->isNum()) { top = obj2.getNum(); changeTop = gTrue; } else if (obj2.isNull()) { changeTop = gFalse; } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } obj2.free(); // FitBV link } else if (obj1.isName("FitBV")) { if (a->getLength() < 3) { error(errSyntaxWarning, -1, "Annotation destination array is too short"); goto err2; } kind = destFitBV; if (a->get(2, &obj2)->isNum()) { left = obj2.getNum(); changeLeft = gTrue; } else if (obj2.isNull()) { changeLeft = gFalse; } else { error(errSyntaxWarning, -1, "Bad annotation destination position"); kind = destFit; } obj2.free(); // unknown link kind } else { error(errSyntaxWarning, -1, "Unknown annotation destination type"); goto err2; } obj1.free(); ok = gTrue; return; err1: obj2.free(); err2: obj1.free(); } LinkDest::LinkDest(LinkDest *dest) { kind = dest->kind; pageIsRef = dest->pageIsRef; if (pageIsRef) pageRef = dest->pageRef; else pageNum = dest->pageNum; left = dest->left; bottom = dest->bottom; right = dest->right; top = dest->top; zoom = dest->zoom; changeLeft = dest->changeLeft; changeTop = dest->changeTop; changeZoom = dest->changeZoom; ok = gTrue; } //------------------------------------------------------------------------ // LinkGoTo //------------------------------------------------------------------------ LinkGoTo::LinkGoTo(Object *destObj) { dest = NULL; namedDest = NULL; // named destination if (destObj->isName()) { namedDest = new GString(destObj->getName()); } else if (destObj->isString()) { namedDest = destObj->getString()->copy(); // destination dictionary } else if (destObj->isArray()) { dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; } // error } else { error(errSyntaxWarning, -1, "Illegal annotation destination"); } } LinkGoTo::~LinkGoTo() { if (dest) delete dest; if (namedDest) delete namedDest; } //------------------------------------------------------------------------ // LinkGoToR //------------------------------------------------------------------------ LinkGoToR::LinkGoToR(Object *fileSpecObj, Object *destObj) { dest = NULL; namedDest = NULL; // get file name fileName = getFileSpecName(fileSpecObj); // named destination if (destObj->isName()) { namedDest = new GString(destObj->getName()); } else if (destObj->isString()) { namedDest = destObj->getString()->copy(); // destination dictionary } else if (destObj->isArray()) { dest = new LinkDest(destObj->getArray()); if (!dest->isOk()) { delete dest; dest = NULL; } // error } else { error(errSyntaxWarning, -1, "Illegal annotation destination"); } } LinkGoToR::~LinkGoToR() { if (fileName) delete fileName; if (dest) delete dest; if (namedDest) delete namedDest; } //------------------------------------------------------------------------ // LinkLaunch //------------------------------------------------------------------------ LinkLaunch::LinkLaunch(Object *actionObj) { Object obj1, obj2; fileName = NULL; params = NULL; if (actionObj->isDict()) { if (!actionObj->dictLookup("F", &obj1)->isNull()) { fileName = getFileSpecName(&obj1); } else { obj1.free(); #ifdef WIN32 if (actionObj->dictLookup("Win", &obj1)->isDict()) { obj1.dictLookup("F", &obj2); fileName = getFileSpecName(&obj2); obj2.free(); if (obj1.dictLookup("P", &obj2)->isString()) { params = obj2.getString()->copy(); } obj2.free(); } else { error(errSyntaxWarning, -1, "Bad launch-type link action"); } #else //~ This hasn't been defined by Adobe yet, so assume it looks //~ just like the Win dictionary until they say otherwise. if (actionObj->dictLookup("Unix", &obj1)->isDict()) { obj1.dictLookup("F", &obj2); fileName = getFileSpecName(&obj2); obj2.free(); if (obj1.dictLookup("P", &obj2)->isString()) { params = obj2.getString()->copy(); } obj2.free(); } else { error(errSyntaxWarning, -1, "Bad launch-type link action"); } #endif } obj1.free(); } } LinkLaunch::~LinkLaunch() { if (fileName) delete fileName; if (params) delete params; } //------------------------------------------------------------------------ // LinkURI //------------------------------------------------------------------------ LinkURI::LinkURI(Object *uriObj, GString *baseURI) { GString *uri2; int n; char c; uri = NULL; if (uriObj->isString()) { uri2 = uriObj->getString(); n = (int)strcspn(uri2->getCString(), "/:"); if (n < uri2->getLength() && uri2->getChar(n) == ':') { // "http:..." etc. uri = uri2->copy(); } else if (!uri2->cmpN("www.", 4)) { // "www.[...]" without the leading "http://" uri = new GString("http://"); uri->append(uri2); } else { // relative URI if (baseURI) { uri = baseURI->copy(); c = uri->getChar(uri->getLength() - 1); if (c != '/' && c != '?') { uri->append('/'); } if (uri2->getChar(0) == '/') { uri->append(uri2->getCString() + 1, uri2->getLength() - 1); } else { uri->append(uri2); } } else { uri = uri2->copy(); } } } else { error(errSyntaxWarning, -1, "Illegal URI-type link"); } } LinkURI::~LinkURI() { if (uri) delete uri; } //------------------------------------------------------------------------ // LinkNamed //------------------------------------------------------------------------ LinkNamed::LinkNamed(Object *nameObj) { name = NULL; if (nameObj->isName()) { name = new GString(nameObj->getName()); } } LinkNamed::~LinkNamed() { if (name) { delete name; } } //------------------------------------------------------------------------ // LinkMovie //------------------------------------------------------------------------ LinkMovie::LinkMovie(Object *annotObj, Object *titleObj) { annotRef.num = -1; title = NULL; if (annotObj->isRef()) { annotRef = annotObj->getRef(); } else if (titleObj->isString()) { title = titleObj->getString()->copy(); } else { error(errSyntaxError, -1, "Movie action is missing both the Annot and T keys"); } } LinkMovie::~LinkMovie() { if (title) { delete title; } } //------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ LinkUnknown::LinkUnknown(char *actionA) { action = new GString(actionA); } LinkUnknown::~LinkUnknown() { delete action; } //------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ Link::Link(Dict *dict, GString *baseURI) { Object obj1, obj2; double t; action = NULL; ok = gFalse; // get rectangle if (!dict->lookup("Rect", &obj1)->isArray()) { error(errSyntaxError, -1, "Annotation rectangle is wrong type"); goto err2; } if (!obj1.arrayGet(0, &obj2)->isNum()) { error(errSyntaxError, -1, "Bad annotation rectangle"); goto err1; } x1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(1, &obj2)->isNum()) { error(errSyntaxError, -1, "Bad annotation rectangle"); goto err1; } y1 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(2, &obj2)->isNum()) { error(errSyntaxError, -1, "Bad annotation rectangle"); goto err1; } x2 = obj2.getNum(); obj2.free(); if (!obj1.arrayGet(3, &obj2)->isNum()) { error(errSyntaxError, -1, "Bad annotation rectangle"); goto err1; } y2 = obj2.getNum(); obj2.free(); obj1.free(); if (x1 > x2) { t = x1; x1 = x2; x2 = t; } if (y1 > y2) { t = y1; y1 = y2; y2 = t; } // look for destination if (!dict->lookup("Dest", &obj1)->isNull()) { action = LinkAction::parseDest(&obj1); // look for action } else { obj1.free(); if (dict->lookup("A", &obj1)->isDict()) { action = LinkAction::parseAction(&obj1, baseURI); } } obj1.free(); // check for bad action if (action) { ok = gTrue; } return; err1: obj2.free(); err2: obj1.free(); } Link::~Link() { if (action) { delete action; } } //------------------------------------------------------------------------ // Links //------------------------------------------------------------------------ Links::Links(Object *annots, GString *baseURI) { Link *link; Object obj1, obj2; int size; int i; links = NULL; size = 0; numLinks = 0; if (annots->isArray()) { for (i = 0; i < annots->arrayGetLength(); ++i) { if (annots->arrayGet(i, &obj1)->isDict()) { if (obj1.dictLookup("Subtype", &obj2)->isName("Link")) { link = new Link(obj1.getDict(), baseURI); if (link->isOk()) { if (numLinks >= size) { size += 16; links = (Link **)greallocn(links, size, sizeof(Link *)); } links[numLinks++] = link; } else { delete link; } } obj2.free(); } obj1.free(); } } } Links::~Links() { int i; for (i = 0; i < numLinks; ++i) delete links[i]; gfree(links); } LinkAction *Links::find(double x, double y) { int i; for (i = numLinks - 1; i >= 0; --i) { if (links[i]->inRect(x, y)) { return links[i]->getAction(); } } return NULL; } GBool Links::onLink(double x, double y) { int i; for (i = 0; i < numLinks; ++i) { if (links[i]->inRect(x, y)) return gTrue; } return gFalse; } xpdf-3.03/xpdf/dblLeftArrowDis.xbm0000644000076400007640000000046111622305345016414 0ustar dereknderekn#define dblLeftArrowDis_width 16 #define dblLeftArrowDis_height 15 static unsigned char dblLeftArrowDis_bits[] = { 0x80, 0x80, 0x40, 0x40, 0xa0, 0xa0, 0x50, 0x50, 0xa8, 0xa8, 0x54, 0x54, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa, 0x54, 0x54, 0xa8, 0xa8, 0x50, 0x50, 0xa0, 0xa0, 0x40, 0x40, 0x80, 0x80}; xpdf-3.03/xpdf/UnicodeMap.h0000644000076400007640000000561411622305345015057 0ustar dereknderekn//======================================================================== // // UnicodeMap.h // // Mapping from Unicode to an encoding. // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef UNICODEMAP_H #define UNICODEMAP_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" #if MULTITHREADED #include "GMutex.h" #endif class GString; //------------------------------------------------------------------------ enum UnicodeMapKind { unicodeMapUser, // read from a file unicodeMapResident, // static list of ranges unicodeMapFunc // function pointer }; typedef int (*UnicodeMapFunc)(Unicode u, char *buf, int bufSize); struct UnicodeMapRange { Unicode start, end; // range of Unicode chars Guint code, nBytes; // first output code }; struct UnicodeMapExt; //------------------------------------------------------------------------ class UnicodeMap { public: // Create the UnicodeMap specified by . Sets the // initial reference count to 1. Returns NULL on failure. static UnicodeMap *parse(GString *encodingNameA); // Create a resident UnicodeMap. UnicodeMap(const char *encodingNameA, GBool unicodeOutA, UnicodeMapRange *rangesA, int lenA); // Create a resident UnicodeMap that uses a function instead of a // list of ranges. UnicodeMap(const char *encodingNameA, GBool unicodeOutA, UnicodeMapFunc funcA); ~UnicodeMap(); void incRefCnt(); void decRefCnt(); GString *getEncodingName() { return encodingName; } GBool isUnicode() { return unicodeOut; } // Return true if this UnicodeMap matches the specified // . GBool match(GString *encodingNameA); // Map Unicode to the target encoding. Fills in with the // output and returns the number of bytes used. Output will be // truncated at bytes. No string terminator is written. // Returns 0 if no mapping is found. int mapUnicode(Unicode u, char *buf, int bufSize); private: UnicodeMap(GString *encodingNameA); GString *encodingName; UnicodeMapKind kind; GBool unicodeOut; union { UnicodeMapRange *ranges; // (user, resident) UnicodeMapFunc func; // (func) }; int len; // (user, resident) UnicodeMapExt *eMaps; // (user) int eMapsLen; // (user) int refCnt; #if MULTITHREADED GMutex mutex; #endif }; //------------------------------------------------------------------------ #define unicodeMapCacheSize 4 class UnicodeMapCache { public: UnicodeMapCache(); ~UnicodeMapCache(); // Get the UnicodeMap for . Increments its reference // count; there will be one reference for the cache plus one for the // caller of this function. Returns NULL on failure. UnicodeMap *getUnicodeMap(GString *encodingName); private: UnicodeMap *cache[unicodeMapCacheSize]; }; #endif xpdf-3.03/xpdf/leftArrow.xbm0000644000076400007640000000030111622305345015323 0ustar dereknderekn#define leftArrow_width 8 #define leftArrow_height 15 static unsigned char leftArrow_bits[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80}; xpdf-3.03/xpdf/GfxState.cc0000644000076400007640000032403111622305345014713 0ustar dereknderekn//======================================================================== // // GfxState.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gmem.h" #include "Error.h" #include "Object.h" #include "Array.h" #include "Page.h" #include "GfxState.h" //------------------------------------------------------------------------ // Max depth of nested color spaces. This is used to catch infinite // loops in the color space object structure. #define colorSpaceRecursionLimit 8 //------------------------------------------------------------------------ static inline GfxColorComp clip01(GfxColorComp x) { return (x < 0) ? 0 : (x > gfxColorComp1) ? gfxColorComp1 : x; } static inline double clip01(double x) { return (x < 0) ? 0 : (x > 1) ? 1 : x; } //------------------------------------------------------------------------ struct GfxBlendModeInfo { const char *name; GfxBlendMode mode; }; static GfxBlendModeInfo gfxBlendModeNames[] = { { "Normal", gfxBlendNormal }, { "Compatible", gfxBlendNormal }, { "Multiply", gfxBlendMultiply }, { "Screen", gfxBlendScreen }, { "Overlay", gfxBlendOverlay }, { "Darken", gfxBlendDarken }, { "Lighten", gfxBlendLighten }, { "ColorDodge", gfxBlendColorDodge }, { "ColorBurn", gfxBlendColorBurn }, { "HardLight", gfxBlendHardLight }, { "SoftLight", gfxBlendSoftLight }, { "Difference", gfxBlendDifference }, { "Exclusion", gfxBlendExclusion }, { "Hue", gfxBlendHue }, { "Saturation", gfxBlendSaturation }, { "Color", gfxBlendColor }, { "Luminosity", gfxBlendLuminosity } }; #define nGfxBlendModeNames \ ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo)))) //------------------------------------------------------------------------ // NB: This must match the GfxColorSpaceMode enum defined in // GfxState.h static const char *gfxColorSpaceModeNames[] = { "DeviceGray", "CalGray", "DeviceRGB", "CalRGB", "DeviceCMYK", "Lab", "ICCBased", "Indexed", "Separation", "DeviceN", "Pattern" }; #define nGfxColorSpaceModes ((sizeof(gfxColorSpaceModeNames) / sizeof(char *))) //------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ GfxColorSpace::GfxColorSpace() { overprintMask = 0x0f; } GfxColorSpace::~GfxColorSpace() { } GfxColorSpace *GfxColorSpace::parse(Object *csObj, int recursion) { GfxColorSpace *cs; Object obj1; if (recursion > colorSpaceRecursionLimit) { error(errSyntaxError, -1, "Loop detected in color space objects"); return NULL; } cs = NULL; if (csObj->isName()) { if (csObj->isName("DeviceGray") || csObj->isName("G")) { cs = new GfxDeviceGrayColorSpace(); } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) { cs = new GfxDeviceRGBColorSpace(); } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else if (csObj->isName("Pattern")) { cs = new GfxPatternColorSpace(NULL); } else { error(errSyntaxError, -1, "Bad color space '{0:s}'", csObj->getName()); } } else if (csObj->isArray() && csObj->arrayGetLength() > 0) { csObj->arrayGet(0, &obj1); if (obj1.isName("DeviceGray") || obj1.isName("G")) { cs = new GfxDeviceGrayColorSpace(); } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) { cs = new GfxDeviceRGBColorSpace(); } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) { cs = new GfxDeviceCMYKColorSpace(); } else if (obj1.isName("CalGray")) { cs = GfxCalGrayColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("CalRGB")) { cs = GfxCalRGBColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("Lab")) { cs = GfxLabColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("ICCBased")) { cs = GfxICCBasedColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("Indexed") || obj1.isName("I")) { cs = GfxIndexedColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("Separation")) { cs = GfxSeparationColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("DeviceN")) { cs = GfxDeviceNColorSpace::parse(csObj->getArray(), recursion); } else if (obj1.isName("Pattern")) { cs = GfxPatternColorSpace::parse(csObj->getArray(), recursion); } else { error(errSyntaxError, -1, "Bad color space"); } obj1.free(); } else { error(errSyntaxError, -1, "Bad color space - expected name or array"); } return cs; } void GfxColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { int i; for (i = 0; i < getNComps(); ++i) { decodeLow[i] = 0; decodeRange[i] = 1; } } int GfxColorSpace::getNumColorSpaceModes() { return nGfxColorSpaceModes; } const char *GfxColorSpace::getColorSpaceModeName(int idx) { return gfxColorSpaceModeNames[idx]; } //------------------------------------------------------------------------ // GfxDeviceGrayColorSpace //------------------------------------------------------------------------ GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() { } GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() { } GfxColorSpace *GfxDeviceGrayColorSpace::copy() { return new GfxDeviceGrayColorSpace(); } void GfxDeviceGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01(color->c[0]); } void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = rgb->g = rgb->b = clip01(color->c[0]); } void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = cmyk->m = cmyk->y = 0; cmyk->k = clip01(gfxColorComp1 - color->c[0]); } void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } //------------------------------------------------------------------------ // GfxCalGrayColorSpace //------------------------------------------------------------------------ GfxCalGrayColorSpace::GfxCalGrayColorSpace() { whiteX = whiteY = whiteZ = 1; blackX = blackY = blackZ = 0; gamma = 1; } GfxCalGrayColorSpace::~GfxCalGrayColorSpace() { } GfxColorSpace *GfxCalGrayColorSpace::copy() { GfxCalGrayColorSpace *cs; cs = new GfxCalGrayColorSpace(); cs->whiteX = whiteX; cs->whiteY = whiteY; cs->whiteZ = whiteZ; cs->blackX = blackX; cs->blackY = blackY; cs->blackZ = blackZ; cs->gamma = gamma; return cs; } GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr, int recursion) { GfxCalGrayColorSpace *cs; Object obj1, obj2, obj3; if (arr->getLength() < 2) { error(errSyntaxError, -1, "Bad CalGray color space"); return NULL; } arr->get(1, &obj1); if (!obj1.isDict()) { error(errSyntaxError, -1, "Bad CalGray color space"); obj1.free(); return NULL; } cs = new GfxCalGrayColorSpace(); if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->whiteX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->whiteY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->whiteZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->blackX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->blackY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->blackZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Gamma", &obj2)->isNum()) { cs->gamma = obj2.getNum(); } obj2.free(); obj1.free(); return cs; } void GfxCalGrayColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01(color->c[0]); } void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = rgb->g = rgb->b = clip01(color->c[0]); } void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = cmyk->m = cmyk->y = 0; cmyk->k = clip01(gfxColorComp1 - color->c[0]); } void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } //------------------------------------------------------------------------ // GfxDeviceRGBColorSpace //------------------------------------------------------------------------ GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() { } GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() { } GfxColorSpace *GfxDeviceRGBColorSpace::copy() { return new GfxDeviceRGBColorSpace(); } void GfxDeviceRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01((GfxColorComp)(0.3 * color->c[0] + 0.59 * color->c[1] + 0.11 * color->c[2] + 0.5)); } void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = clip01(color->c[0]); rgb->g = clip01(color->c[1]); rgb->b = clip01(color->c[2]); } void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColorComp c, m, y, k; c = clip01(gfxColorComp1 - color->c[0]); m = clip01(gfxColorComp1 - color->c[1]); y = clip01(gfxColorComp1 - color->c[2]); k = c; if (m < k) { k = m; } if (y < k) { k = y; } cmyk->c = c - k; cmyk->m = m - k; cmyk->y = y - k; cmyk->k = k; } void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; color->c[2] = 0; } //------------------------------------------------------------------------ // GfxCalRGBColorSpace //------------------------------------------------------------------------ GfxCalRGBColorSpace::GfxCalRGBColorSpace() { whiteX = whiteY = whiteZ = 1; blackX = blackY = blackZ = 0; gammaR = gammaG = gammaB = 1; mat[0] = 1; mat[1] = 0; mat[2] = 0; mat[3] = 0; mat[4] = 1; mat[5] = 0; mat[6] = 0; mat[7] = 0; mat[8] = 1; } GfxCalRGBColorSpace::~GfxCalRGBColorSpace() { } GfxColorSpace *GfxCalRGBColorSpace::copy() { GfxCalRGBColorSpace *cs; int i; cs = new GfxCalRGBColorSpace(); cs->whiteX = whiteX; cs->whiteY = whiteY; cs->whiteZ = whiteZ; cs->blackX = blackX; cs->blackY = blackY; cs->blackZ = blackZ; cs->gammaR = gammaR; cs->gammaG = gammaG; cs->gammaB = gammaB; for (i = 0; i < 9; ++i) { cs->mat[i] = mat[i]; } return cs; } GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr, int recursion) { GfxCalRGBColorSpace *cs; Object obj1, obj2, obj3; int i; if (arr->getLength() < 2) { error(errSyntaxError, -1, "Bad CalRGB color space"); return NULL; } arr->get(1, &obj1); if (!obj1.isDict()) { error(errSyntaxError, -1, "Bad CalRGB color space"); obj1.free(); return NULL; } cs = new GfxCalRGBColorSpace(); if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->whiteX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->whiteY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->whiteZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->blackX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->blackY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->blackZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Gamma", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->gammaR = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->gammaG = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->gammaB = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Matrix", &obj2)->isArray() && obj2.arrayGetLength() == 9) { for (i = 0; i < 9; ++i) { obj2.arrayGet(i, &obj3); cs->mat[i] = obj3.getNum(); obj3.free(); } } obj2.free(); obj1.free(); return cs; } void GfxCalRGBColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01((GfxColorComp)(0.299 * color->c[0] + 0.587 * color->c[1] + 0.114 * color->c[2] + 0.5)); } void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = clip01(color->c[0]); rgb->g = clip01(color->c[1]); rgb->b = clip01(color->c[2]); } void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColorComp c, m, y, k; c = clip01(gfxColorComp1 - color->c[0]); m = clip01(gfxColorComp1 - color->c[1]); y = clip01(gfxColorComp1 - color->c[2]); k = c; if (m < k) { k = m; } if (y < k) { k = y; } cmyk->c = c - k; cmyk->m = m - k; cmyk->y = y - k; cmyk->k = k; } void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; color->c[2] = 0; } //------------------------------------------------------------------------ // GfxDeviceCMYKColorSpace //------------------------------------------------------------------------ GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() { } GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() { } GfxColorSpace *GfxDeviceCMYKColorSpace::copy() { return new GfxDeviceCMYKColorSpace(); } void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = clip01((GfxColorComp)(gfxColorComp1 - color->c[3] - 0.3 * color->c[0] - 0.59 * color->c[1] - 0.11 * color->c[2] + 0.5)); } void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { double c, m, y, k, c1, m1, y1, k1, r, g, b, x; c = colToDbl(color->c[0]); m = colToDbl(color->c[1]); y = colToDbl(color->c[2]); k = colToDbl(color->c[3]); c1 = 1 - c; m1 = 1 - m; y1 = 1 - y; k1 = 1 - k; // this is a matrix multiplication, unrolled for performance // C M Y K x = c1 * m1 * y1 * k1; // 0 0 0 0 r = g = b = x; x = c1 * m1 * y1 * k; // 0 0 0 1 r += 0.1373 * x; g += 0.1216 * x; b += 0.1255 * x; x = c1 * m1 * y * k1; // 0 0 1 0 r += x; g += 0.9490 * x; x = c1 * m1 * y * k; // 0 0 1 1 r += 0.1098 * x; g += 0.1020 * x; x = c1 * m * y1 * k1; // 0 1 0 0 r += 0.9255 * x; b += 0.5490 * x; x = c1 * m * y1 * k; // 0 1 0 1 r += 0.1412 * x; x = c1 * m * y * k1; // 0 1 1 0 r += 0.9294 * x; g += 0.1098 * x; b += 0.1412 * x; x = c1 * m * y * k; // 0 1 1 1 r += 0.1333 * x; x = c * m1 * y1 * k1; // 1 0 0 0 g += 0.6784 * x; b += 0.9373 * x; x = c * m1 * y1 * k; // 1 0 0 1 g += 0.0588 * x; b += 0.1412 * x; x = c * m1 * y * k1; // 1 0 1 0 g += 0.6510 * x; b += 0.3137 * x; x = c * m1 * y * k; // 1 0 1 1 g += 0.0745 * x; x = c * m * y1 * k1; // 1 1 0 0 r += 0.1804 * x; g += 0.1922 * x; b += 0.5725 * x; x = c * m * y1 * k; // 1 1 0 1 b += 0.0078 * x; x = c * m * y * k1; // 1 1 1 0 r += 0.2118 * x; g += 0.2119 * x; b += 0.2235 * x; rgb->r = clip01(dblToCol(r)); rgb->g = clip01(dblToCol(g)); rgb->b = clip01(dblToCol(b)); } void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = clip01(color->c[0]); cmyk->m = clip01(color->c[1]); cmyk->y = clip01(color->c[2]); cmyk->k = clip01(color->c[3]); } void GfxDeviceCMYKColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; color->c[1] = 0; color->c[2] = 0; color->c[3] = gfxColorComp1; } //------------------------------------------------------------------------ // GfxLabColorSpace //------------------------------------------------------------------------ // This is the inverse of MatrixLMN in Example 4.10 from the PostScript // Language Reference, Third Edition. static double xyzrgb[3][3] = { { 3.240449, -1.537136, -0.498531 }, { -0.969265, 1.876011, 0.041556 }, { 0.055643, -0.204026, 1.057229 } }; GfxLabColorSpace::GfxLabColorSpace() { whiteX = whiteY = whiteZ = 1; blackX = blackY = blackZ = 0; aMin = bMin = -100; aMax = bMax = 100; } GfxLabColorSpace::~GfxLabColorSpace() { } GfxColorSpace *GfxLabColorSpace::copy() { GfxLabColorSpace *cs; cs = new GfxLabColorSpace(); cs->whiteX = whiteX; cs->whiteY = whiteY; cs->whiteZ = whiteZ; cs->blackX = blackX; cs->blackY = blackY; cs->blackZ = blackZ; cs->aMin = aMin; cs->aMax = aMax; cs->bMin = bMin; cs->bMax = bMax; cs->kr = kr; cs->kg = kg; cs->kb = kb; return cs; } GfxColorSpace *GfxLabColorSpace::parse(Array *arr, int recursion) { GfxLabColorSpace *cs; Object obj1, obj2, obj3; if (arr->getLength() < 2) { error(errSyntaxError, -1, "Bad Lab color space"); return NULL; } arr->get(1, &obj1); if (!obj1.isDict()) { error(errSyntaxError, -1, "Bad Lab color space"); obj1.free(); return NULL; } cs = new GfxLabColorSpace(); if (obj1.dictLookup("WhitePoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->whiteX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->whiteY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->whiteZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("BlackPoint", &obj2)->isArray() && obj2.arrayGetLength() == 3) { obj2.arrayGet(0, &obj3); cs->blackX = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->blackY = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->blackZ = obj3.getNum(); obj3.free(); } obj2.free(); if (obj1.dictLookup("Range", &obj2)->isArray() && obj2.arrayGetLength() == 4) { obj2.arrayGet(0, &obj3); cs->aMin = obj3.getNum(); obj3.free(); obj2.arrayGet(1, &obj3); cs->aMax = obj3.getNum(); obj3.free(); obj2.arrayGet(2, &obj3); cs->bMin = obj3.getNum(); obj3.free(); obj2.arrayGet(3, &obj3); cs->bMax = obj3.getNum(); obj3.free(); } obj2.free(); obj1.free(); cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX + xyzrgb[0][1] * cs->whiteY + xyzrgb[0][2] * cs->whiteZ); cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX + xyzrgb[1][1] * cs->whiteY + xyzrgb[1][2] * cs->whiteZ); cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX + xyzrgb[2][1] * cs->whiteY + xyzrgb[2][2] * cs->whiteZ); return cs; } void GfxLabColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxRGB rgb; getRGB(color, &rgb); *gray = clip01((GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b + 0.5)); } void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { double X, Y, Z; double t1, t2; double r, g, b; // convert L*a*b* to CIE 1931 XYZ color space t1 = (colToDbl(color->c[0]) + 16) / 116; t2 = t1 + colToDbl(color->c[1]) / 500; if (t2 >= (6.0 / 29.0)) { X = t2 * t2 * t2; } else { X = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); } X *= whiteX; if (t1 >= (6.0 / 29.0)) { Y = t1 * t1 * t1; } else { Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0)); } Y *= whiteY; t2 = t1 - colToDbl(color->c[2]) / 200; if (t2 >= (6.0 / 29.0)) { Z = t2 * t2 * t2; } else { Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0)); } Z *= whiteZ; // convert XYZ to RGB, including gamut mapping and gamma correction r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z; g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z; b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z; rgb->r = dblToCol(pow(clip01(r * kr), 0.5)); rgb->g = dblToCol(pow(clip01(g * kg), 0.5)); rgb->b = dblToCol(pow(clip01(b * kb), 0.5)); } void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxRGB rgb; GfxColorComp c, m, y, k; getRGB(color, &rgb); c = clip01(gfxColorComp1 - rgb.r); m = clip01(gfxColorComp1 - rgb.g); y = clip01(gfxColorComp1 - rgb.b); k = c; if (m < k) { k = m; } if (y < k) { k = y; } cmyk->c = c - k; cmyk->m = m - k; cmyk->y = y - k; cmyk->k = k; } void GfxLabColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; if (aMin > 0) { color->c[1] = dblToCol(aMin); } else if (aMax < 0) { color->c[1] = dblToCol(aMax); } else { color->c[1] = 0; } if (bMin > 0) { color->c[2] = dblToCol(bMin); } else if (bMax < 0) { color->c[2] = dblToCol(bMax); } else { color->c[2] = 0; } } void GfxLabColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { decodeLow[0] = 0; decodeRange[0] = 100; decodeLow[1] = aMin; decodeRange[1] = aMax - aMin; decodeLow[2] = bMin; decodeRange[2] = bMax - bMin; } //------------------------------------------------------------------------ // GfxICCBasedColorSpace //------------------------------------------------------------------------ GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, Ref *iccProfileStreamA) { nComps = nCompsA; alt = altA; iccProfileStream = *iccProfileStreamA; rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0; rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1; } GfxICCBasedColorSpace::~GfxICCBasedColorSpace() { delete alt; } GfxColorSpace *GfxICCBasedColorSpace::copy() { GfxICCBasedColorSpace *cs; int i; cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream); for (i = 0; i < 4; ++i) { cs->rangeMin[i] = rangeMin[i]; cs->rangeMax[i] = rangeMax[i]; } return cs; } GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr, int recursion) { GfxICCBasedColorSpace *cs; Ref iccProfileStreamA; int nCompsA; GfxColorSpace *altA; Dict *dict; Object obj1, obj2, obj3; int i; if (arr->getLength() < 2) { error(errSyntaxError, -1, "Bad ICCBased color space"); return NULL; } arr->getNF(1, &obj1); if (obj1.isRef()) { iccProfileStreamA = obj1.getRef(); } else { iccProfileStreamA.num = 0; iccProfileStreamA.gen = 0; } obj1.free(); arr->get(1, &obj1); if (!obj1.isStream()) { error(errSyntaxError, -1, "Bad ICCBased color space (stream)"); obj1.free(); return NULL; } dict = obj1.streamGetDict(); if (!dict->lookup("N", &obj2)->isInt()) { error(errSyntaxError, -1, "Bad ICCBased color space (N)"); obj2.free(); obj1.free(); return NULL; } nCompsA = obj2.getInt(); obj2.free(); if (nCompsA > 4) { error(errSyntaxError, -1, "ICCBased color space with too many ({0:d} > 4) components", nCompsA); nCompsA = 4; } if (dict->lookup("Alternate", &obj2)->isNull() || !(altA = GfxColorSpace::parse(&obj2, recursion + 1))) { switch (nCompsA) { case 1: altA = new GfxDeviceGrayColorSpace(); break; case 3: altA = new GfxDeviceRGBColorSpace(); break; case 4: altA = new GfxDeviceCMYKColorSpace(); break; default: error(errSyntaxError, -1, "Bad ICCBased color space - invalid N"); obj2.free(); obj1.free(); return NULL; } } obj2.free(); cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA); if (dict->lookup("Range", &obj2)->isArray() && obj2.arrayGetLength() == 2 * nCompsA) { for (i = 0; i < nCompsA; ++i) { obj2.arrayGet(2*i, &obj3); cs->rangeMin[i] = obj3.getNum(); obj3.free(); obj2.arrayGet(2*i+1, &obj3); cs->rangeMax[i] = obj3.getNum(); obj3.free(); } } obj2.free(); obj1.free(); return cs; } void GfxICCBasedColorSpace::getGray(GfxColor *color, GfxGray *gray) { alt->getGray(color, gray); } void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { alt->getRGB(color, rgb); } void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { alt->getCMYK(color, cmyk); } void GfxICCBasedColorSpace::getDefaultColor(GfxColor *color) { int i; for (i = 0; i < nComps; ++i) { if (rangeMin[i] > 0) { color->c[i] = dblToCol(rangeMin[i]); } else if (rangeMax[i] < 0) { color->c[i] = dblToCol(rangeMax[i]); } else { color->c[i] = 0; } } } void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); #if 0 // this is nominally correct, but some PDF files don't set the // correct ranges in the ICCBased dict int i; for (i = 0; i < nComps; ++i) { decodeLow[i] = rangeMin[i]; decodeRange[i] = rangeMax[i] - rangeMin[i]; } #endif } //------------------------------------------------------------------------ // GfxIndexedColorSpace //------------------------------------------------------------------------ GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA) { base = baseA; indexHigh = indexHighA; lookup = (Guchar *)gmallocn((indexHigh + 1) * base->getNComps(), sizeof(Guchar)); overprintMask = base->getOverprintMask(); } GfxIndexedColorSpace::~GfxIndexedColorSpace() { delete base; gfree(lookup); } GfxColorSpace *GfxIndexedColorSpace::copy() { GfxIndexedColorSpace *cs; cs = new GfxIndexedColorSpace(base->copy(), indexHigh); memcpy(cs->lookup, lookup, (indexHigh + 1) * base->getNComps() * sizeof(Guchar)); return cs; } GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr, int recursion) { GfxIndexedColorSpace *cs; GfxColorSpace *baseA; int indexHighA; Object obj1; int x; char *s; int n, i, j; if (arr->getLength() != 4) { error(errSyntaxError, -1, "Bad Indexed color space"); goto err1; } arr->get(1, &obj1); if (!(baseA = GfxColorSpace::parse(&obj1, recursion + 1))) { error(errSyntaxError, -1, "Bad Indexed color space (base color space)"); goto err2; } obj1.free(); if (!arr->get(2, &obj1)->isInt()) { error(errSyntaxError, -1, "Bad Indexed color space (hival)"); delete baseA; goto err2; } indexHighA = obj1.getInt(); if (indexHighA < 0 || indexHighA > 255) { // the PDF spec requires indexHigh to be in [0,255] -- allowing // values larger than 255 creates a security hole: if nComps * // indexHigh is greater than 2^31, the loop below may overwrite // past the end of the array error(errSyntaxError, -1, "Bad Indexed color space (invalid indexHigh value)"); delete baseA; goto err2; } obj1.free(); cs = new GfxIndexedColorSpace(baseA, indexHighA); arr->get(3, &obj1); n = baseA->getNComps(); if (obj1.isStream()) { obj1.streamReset(); for (i = 0; i <= indexHighA; ++i) { for (j = 0; j < n; ++j) { if ((x = obj1.streamGetChar()) == EOF) { error(errSyntaxError, -1, "Bad Indexed color space (lookup table stream too short)"); cs->indexHigh = indexHighA = i - 1; } cs->lookup[i*n + j] = (Guchar)x; } } obj1.streamClose(); } else if (obj1.isString()) { if (obj1.getString()->getLength() < (indexHighA + 1) * n) { error(errSyntaxError, -1, "Bad Indexed color space (lookup table string too short)"); cs->indexHigh = indexHighA = obj1.getString()->getLength() / n - 1; } s = obj1.getString()->getCString(); for (i = 0; i <= indexHighA; ++i) { for (j = 0; j < n; ++j) { cs->lookup[i*n + j] = (Guchar)*s++; } } } else { error(errSyntaxError, -1, "Bad Indexed color space (lookup table)"); goto err3; } obj1.free(); return cs; err3: delete cs; err2: obj1.free(); err1: return NULL; } GfxColor *GfxIndexedColorSpace::mapColorToBase(GfxColor *color, GfxColor *baseColor) { Guchar *p; double low[gfxColorMaxComps], range[gfxColorMaxComps]; int n, i; n = base->getNComps(); base->getDefaultRanges(low, range, indexHigh); p = &lookup[(int)(colToDbl(color->c[0]) + 0.5) * n]; for (i = 0; i < n; ++i) { baseColor->c[i] = dblToCol(low[i] + (p[i] / 255.0) * range[i]); } return baseColor; } void GfxIndexedColorSpace::getGray(GfxColor *color, GfxGray *gray) { GfxColor color2; base->getGray(mapColorToBase(color, &color2), gray); } void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { GfxColor color2; base->getRGB(mapColorToBase(color, &color2), rgb); } void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { GfxColor color2; base->getCMYK(mapColorToBase(color, &color2), cmyk); } void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = 0; } void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { decodeLow[0] = 0; decodeRange[0] = maxImgPixel; } //------------------------------------------------------------------------ // GfxSeparationColorSpace //------------------------------------------------------------------------ GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, Function *funcA) { name = nameA; alt = altA; func = funcA; nonMarking = !name->cmp("None"); if (!name->cmp("Cyan")) { overprintMask = 0x01; } else if (!name->cmp("Magenta")) { overprintMask = 0x02; } else if (!name->cmp("Yellow")) { overprintMask = 0x04; } else if (!name->cmp("Black")) { overprintMask = 0x08; } } GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, Function *funcA, GBool nonMarkingA, Guint overprintMaskA) { name = nameA; alt = altA; func = funcA; nonMarking = nonMarkingA; overprintMask = overprintMaskA; } GfxSeparationColorSpace::~GfxSeparationColorSpace() { delete name; delete alt; delete func; } GfxColorSpace *GfxSeparationColorSpace::copy() { return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy(), nonMarking, overprintMask); } //~ handle the 'All' and 'None' colorants GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr, int recursion) { GfxSeparationColorSpace *cs; GString *nameA; GfxColorSpace *altA; Function *funcA; Object obj1; if (arr->getLength() != 4) { error(errSyntaxError, -1, "Bad Separation color space"); goto err1; } if (!arr->get(1, &obj1)->isName()) { error(errSyntaxError, -1, "Bad Separation color space (name)"); goto err2; } nameA = new GString(obj1.getName()); obj1.free(); arr->get(2, &obj1); if (!(altA = GfxColorSpace::parse(&obj1, recursion + 1))) { error(errSyntaxError, -1, "Bad Separation color space (alternate color space)"); goto err3; } obj1.free(); arr->get(3, &obj1); if (!(funcA = Function::parse(&obj1))) { goto err4; } obj1.free(); cs = new GfxSeparationColorSpace(nameA, altA, funcA); return cs; err4: delete altA; err3: delete nameA; err2: obj1.free(); err1: return NULL; } void GfxSeparationColorSpace::getGray(GfxColor *color, GfxGray *gray) { double x; double c[gfxColorMaxComps]; GfxColor color2; int i; x = colToDbl(color->c[0]); func->transform(&x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getGray(&color2, gray); } void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { double x; double c[gfxColorMaxComps]; GfxColor color2; int i; x = colToDbl(color->c[0]); func->transform(&x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getRGB(&color2, rgb); } void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { double x; double c[gfxColorMaxComps]; GfxColor color2; int i; x = colToDbl(color->c[0]); func->transform(&x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getCMYK(&color2, cmyk); } void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { color->c[0] = gfxColorComp1; } //------------------------------------------------------------------------ // GfxDeviceNColorSpace //------------------------------------------------------------------------ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, GString **namesA, GfxColorSpace *altA, Function *funcA) { int i; nComps = nCompsA; alt = altA; func = funcA; nonMarking = gTrue; overprintMask = 0; for (i = 0; i < nComps; ++i) { names[i] = namesA[i]; if (names[i]->cmp("None")) { nonMarking = gFalse; } if (!names[i]->cmp("Cyan")) { overprintMask |= 0x01; } else if (!names[i]->cmp("Magenta")) { overprintMask |= 0x02; } else if (!names[i]->cmp("Yellow")) { overprintMask |= 0x04; } else if (!names[i]->cmp("Black")) { overprintMask |= 0x08; } else { overprintMask = 0x0f; } } } GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, GString **namesA, GfxColorSpace *altA, Function *funcA, GBool nonMarkingA, Guint overprintMaskA) { int i; nComps = nCompsA; alt = altA; func = funcA; nonMarking = nonMarkingA; overprintMask = overprintMaskA; for (i = 0; i < nComps; ++i) { names[i] = namesA[i]->copy(); } } GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { int i; for (i = 0; i < nComps; ++i) { delete names[i]; } delete alt; delete func; } GfxColorSpace *GfxDeviceNColorSpace::copy() { return new GfxDeviceNColorSpace(nComps, names, alt->copy(), func->copy(), nonMarking, overprintMask); } //~ handle the 'None' colorant GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr, int recursion) { GfxDeviceNColorSpace *cs; int nCompsA; GString *namesA[gfxColorMaxComps]; GfxColorSpace *altA; Function *funcA; Object obj1, obj2; int i; if (arr->getLength() != 4 && arr->getLength() != 5) { error(errSyntaxError, -1, "Bad DeviceN color space"); goto err1; } if (!arr->get(1, &obj1)->isArray()) { error(errSyntaxError, -1, "Bad DeviceN color space (names)"); goto err2; } nCompsA = obj1.arrayGetLength(); if (nCompsA > gfxColorMaxComps) { error(errSyntaxError, -1, "DeviceN color space with too many ({0:d} > {1:d}) components", nCompsA, gfxColorMaxComps); nCompsA = gfxColorMaxComps; } for (i = 0; i < nCompsA; ++i) { if (!obj1.arrayGet(i, &obj2)->isName()) { error(errSyntaxError, -1, "Bad DeviceN color space (names)"); obj2.free(); goto err2; } namesA[i] = new GString(obj2.getName()); obj2.free(); } obj1.free(); arr->get(2, &obj1); if (!(altA = GfxColorSpace::parse(&obj1, recursion + 1))) { error(errSyntaxError, -1, "Bad DeviceN color space (alternate color space)"); goto err3; } obj1.free(); arr->get(3, &obj1); if (!(funcA = Function::parse(&obj1))) { goto err4; } obj1.free(); cs = new GfxDeviceNColorSpace(nCompsA, namesA, altA, funcA); return cs; err4: delete altA; err3: for (i = 0; i < nCompsA; ++i) { delete namesA[i]; } err2: obj1.free(); err1: return NULL; } void GfxDeviceNColorSpace::getGray(GfxColor *color, GfxGray *gray) { double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; int i; for (i = 0; i < nComps; ++i) { x[i] = colToDbl(color->c[i]); } func->transform(x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getGray(&color2, gray); } void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; int i; for (i = 0; i < nComps; ++i) { x[i] = colToDbl(color->c[i]); } func->transform(x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getRGB(&color2, rgb); } void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { double x[gfxColorMaxComps], c[gfxColorMaxComps]; GfxColor color2; int i; for (i = 0; i < nComps; ++i) { x[i] = colToDbl(color->c[i]); } func->transform(x, c); for (i = 0; i < alt->getNComps(); ++i) { color2.c[i] = dblToCol(c[i]); } alt->getCMYK(&color2, cmyk); } void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { int i; for (i = 0; i < nComps; ++i) { color->c[i] = gfxColorComp1; } } //------------------------------------------------------------------------ // GfxPatternColorSpace //------------------------------------------------------------------------ GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) { under = underA; } GfxPatternColorSpace::~GfxPatternColorSpace() { if (under) { delete under; } } GfxColorSpace *GfxPatternColorSpace::copy() { return new GfxPatternColorSpace(under ? under->copy() : (GfxColorSpace *)NULL); } GfxColorSpace *GfxPatternColorSpace::parse(Array *arr, int recursion) { GfxPatternColorSpace *cs; GfxColorSpace *underA; Object obj1; if (arr->getLength() != 1 && arr->getLength() != 2) { error(errSyntaxError, -1, "Bad Pattern color space"); return NULL; } underA = NULL; if (arr->getLength() == 2) { arr->get(1, &obj1); if (!(underA = GfxColorSpace::parse(&obj1, recursion + 1))) { error(errSyntaxError, -1, "Bad Pattern color space (underlying color space)"); obj1.free(); return NULL; } obj1.free(); } cs = new GfxPatternColorSpace(underA); return cs; } void GfxPatternColorSpace::getGray(GfxColor *color, GfxGray *gray) { *gray = 0; } void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) { rgb->r = rgb->g = rgb->b = 0; } void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->c = cmyk->m = cmyk->y = 0; cmyk->k = 1; } void GfxPatternColorSpace::getDefaultColor(GfxColor *color) { // not used } //------------------------------------------------------------------------ // Pattern //------------------------------------------------------------------------ GfxPattern::GfxPattern(int typeA) { type = typeA; } GfxPattern::~GfxPattern() { } GfxPattern *GfxPattern::parse(Object *obj) { GfxPattern *pattern; Object obj1; if (obj->isDict()) { obj->dictLookup("PatternType", &obj1); } else if (obj->isStream()) { obj->streamGetDict()->lookup("PatternType", &obj1); } else { return NULL; } pattern = NULL; if (obj1.isInt() && obj1.getInt() == 1) { pattern = GfxTilingPattern::parse(obj); } else if (obj1.isInt() && obj1.getInt() == 2) { pattern = GfxShadingPattern::parse(obj); } obj1.free(); return pattern; } //------------------------------------------------------------------------ // GfxTilingPattern //------------------------------------------------------------------------ GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) { GfxTilingPattern *pat; Dict *dict; int paintTypeA, tilingTypeA; double bboxA[4], matrixA[6]; double xStepA, yStepA; Object resDictA; Object obj1, obj2; int i; if (!patObj->isStream()) { return NULL; } dict = patObj->streamGetDict(); if (dict->lookup("PaintType", &obj1)->isInt()) { paintTypeA = obj1.getInt(); } else { paintTypeA = 1; error(errSyntaxWarning, -1, "Invalid or missing PaintType in pattern"); } obj1.free(); if (dict->lookup("TilingType", &obj1)->isInt()) { tilingTypeA = obj1.getInt(); } else { tilingTypeA = 1; error(errSyntaxWarning, -1, "Invalid or missing TilingType in pattern"); } obj1.free(); bboxA[0] = bboxA[1] = 0; bboxA[2] = bboxA[3] = 1; if (dict->lookup("BBox", &obj1)->isArray() && obj1.arrayGetLength() == 4) { for (i = 0; i < 4; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { bboxA[i] = obj2.getNum(); } obj2.free(); } } else { error(errSyntaxError, -1, "Invalid or missing BBox in pattern"); } obj1.free(); if (dict->lookup("XStep", &obj1)->isNum()) { xStepA = obj1.getNum(); } else { xStepA = 1; error(errSyntaxError, -1, "Invalid or missing XStep in pattern"); } obj1.free(); if (dict->lookup("YStep", &obj1)->isNum()) { yStepA = obj1.getNum(); } else { yStepA = 1; error(errSyntaxError, -1, "Invalid or missing YStep in pattern"); } obj1.free(); if (!dict->lookup("Resources", &resDictA)->isDict()) { resDictA.free(); resDictA.initNull(); error(errSyntaxError, -1, "Invalid or missing Resources in pattern"); } matrixA[0] = 1; matrixA[1] = 0; matrixA[2] = 0; matrixA[3] = 1; matrixA[4] = 0; matrixA[5] = 0; if (dict->lookup("Matrix", &obj1)->isArray() && obj1.arrayGetLength() == 6) { for (i = 0; i < 6; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { matrixA[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA, &resDictA, matrixA, patObj); resDictA.free(); return pat; } GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA, double *bboxA, double xStepA, double yStepA, Object *resDictA, double *matrixA, Object *contentStreamA): GfxPattern(1) { int i; paintType = paintTypeA; tilingType = tilingTypeA; for (i = 0; i < 4; ++i) { bbox[i] = bboxA[i]; } xStep = xStepA; yStep = yStepA; resDictA->copy(&resDict); for (i = 0; i < 6; ++i) { matrix[i] = matrixA[i]; } contentStreamA->copy(&contentStream); } GfxTilingPattern::~GfxTilingPattern() { resDict.free(); contentStream.free(); } GfxPattern *GfxTilingPattern::copy() { return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep, &resDict, matrix, &contentStream); } //------------------------------------------------------------------------ // GfxShadingPattern //------------------------------------------------------------------------ GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) { Dict *dict; GfxShading *shadingA; double matrixA[6]; Object obj1, obj2; int i; if (!patObj->isDict()) { return NULL; } dict = patObj->getDict(); dict->lookup("Shading", &obj1); shadingA = GfxShading::parse(&obj1); obj1.free(); if (!shadingA) { return NULL; } matrixA[0] = 1; matrixA[1] = 0; matrixA[2] = 0; matrixA[3] = 1; matrixA[4] = 0; matrixA[5] = 0; if (dict->lookup("Matrix", &obj1)->isArray() && obj1.arrayGetLength() == 6) { for (i = 0; i < 6; ++i) { if (obj1.arrayGet(i, &obj2)->isNum()) { matrixA[i] = obj2.getNum(); } obj2.free(); } } obj1.free(); return new GfxShadingPattern(shadingA, matrixA); } GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA): GfxPattern(2) { int i; shading = shadingA; for (i = 0; i < 6; ++i) { matrix[i] = matrixA[i]; } } GfxShadingPattern::~GfxShadingPattern() { delete shading; } GfxPattern *GfxShadingPattern::copy() { return new GfxShadingPattern(shading->copy(), matrix); } //------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ GfxShading::GfxShading(int typeA) { type = typeA; colorSpace = NULL; } GfxShading::GfxShading(GfxShading *shading) { int i; type = shading->type; colorSpace = shading->colorSpace->copy(); for (i = 0; i < gfxColorMaxComps; ++i) { background.c[i] = shading->background.c[i]; } hasBackground = shading->hasBackground; xMin = shading->xMin; yMin = shading->yMin; xMax = shading->xMax; yMax = shading->yMax; hasBBox = shading->hasBBox; } GfxShading::~GfxShading() { if (colorSpace) { delete colorSpace; } } GfxShading *GfxShading::parse(Object *obj) { GfxShading *shading; Dict *dict; int typeA; Object obj1; if (obj->isDict()) { dict = obj->getDict(); } else if (obj->isStream()) { dict = obj->streamGetDict(); } else { return NULL; } if (!dict->lookup("ShadingType", &obj1)->isInt()) { error(errSyntaxError, -1, "Invalid ShadingType in shading dictionary"); obj1.free(); return NULL; } typeA = obj1.getInt(); obj1.free(); switch (typeA) { case 1: shading = GfxFunctionShading::parse(dict); break; case 2: shading = GfxAxialShading::parse(dict); break; case 3: shading = GfxRadialShading::parse(dict); break; case 4: if (obj->isStream()) { shading = GfxGouraudTriangleShading::parse(4, dict, obj->getStream()); } else { error(errSyntaxError, -1, "Invalid Type 4 shading object"); goto err1; } break; case 5: if (obj->isStream()) { shading = GfxGouraudTriangleShading::parse(5, dict, obj->getStream()); } else { error(errSyntaxError, -1, "Invalid Type 5 shading object"); goto err1; } break; case 6: if (obj->isStream()) { shading = GfxPatchMeshShading::parse(6, dict, obj->getStream()); } else { error(errSyntaxError, -1, "Invalid Type 6 shading object"); goto err1; } break; case 7: if (obj->isStream()) { shading = GfxPatchMeshShading::parse(7, dict, obj->getStream()); } else { error(errSyntaxError, -1, "Invalid Type 7 shading object"); goto err1; } break; default: error(errSyntaxError, -1, "Unknown shading type {0:d}", typeA); goto err1; } return shading; err1: return NULL; } GBool GfxShading::init(Dict *dict) { Object obj1, obj2; int i; dict->lookup("ColorSpace", &obj1); if (!(colorSpace = GfxColorSpace::parse(&obj1))) { error(errSyntaxError, -1, "Bad color space in shading dictionary"); obj1.free(); return gFalse; } obj1.free(); for (i = 0; i < gfxColorMaxComps; ++i) { background.c[i] = 0; } hasBackground = gFalse; if (dict->lookup("Background", &obj1)->isArray()) { if (obj1.arrayGetLength() == colorSpace->getNComps()) { hasBackground = gTrue; for (i = 0; i < colorSpace->getNComps(); ++i) { background.c[i] = dblToCol(obj1.arrayGet(i, &obj2)->getNum()); obj2.free(); } } else { error(errSyntaxError, -1, "Bad Background in shading dictionary"); } } obj1.free(); xMin = yMin = xMax = yMax = 0; hasBBox = gFalse; if (dict->lookup("BBox", &obj1)->isArray()) { if (obj1.arrayGetLength() == 4) { hasBBox = gTrue; xMin = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); yMin = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); xMax = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); yMax = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); } else { error(errSyntaxError, -1, "Bad BBox in shading dictionary"); } } obj1.free(); return gTrue; } //------------------------------------------------------------------------ // GfxFunctionShading //------------------------------------------------------------------------ GfxFunctionShading::GfxFunctionShading(double x0A, double y0A, double x1A, double y1A, double *matrixA, Function **funcsA, int nFuncsA): GfxShading(1) { int i; x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; for (i = 0; i < 6; ++i) { matrix[i] = matrixA[i]; } nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } } GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading): GfxShading(shading) { int i; x0 = shading->x0; y0 = shading->y0; x1 = shading->x1; y1 = shading->y1; for (i = 0; i < 6; ++i) { matrix[i] = shading->matrix[i]; } nFuncs = shading->nFuncs; for (i = 0; i < nFuncs; ++i) { funcs[i] = shading->funcs[i]->copy(); } } GfxFunctionShading::~GfxFunctionShading() { int i; for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) { GfxFunctionShading *shading; double x0A, y0A, x1A, y1A; double matrixA[6]; Function *funcsA[gfxColorMaxComps]; int nFuncsA; Object obj1, obj2; int i; x0A = y0A = 0; x1A = y1A = 1; if (dict->lookup("Domain", &obj1)->isArray() && obj1.arrayGetLength() == 4) { x0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); y0A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); x1A = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); y1A = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); } obj1.free(); matrixA[0] = 1; matrixA[1] = 0; matrixA[2] = 0; matrixA[3] = 1; matrixA[4] = 0; matrixA[5] = 0; if (dict->lookup("Matrix", &obj1)->isArray() && obj1.arrayGetLength() == 6) { matrixA[0] = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); matrixA[1] = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); matrixA[2] = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); matrixA[3] = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); matrixA[4] = obj1.arrayGet(4, &obj2)->getNum(); obj2.free(); matrixA[5] = obj1.arrayGet(5, &obj2)->getNum(); obj2.free(); } obj1.free(); dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); if (nFuncsA > gfxColorMaxComps) { error(errSyntaxError, -1, "Invalid Function array in shading dictionary"); goto err1; } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { goto err2; } obj2.free(); } } else { nFuncsA = 1; if (!(funcsA[0] = Function::parse(&obj1))) { goto err1; } } obj1.free(); shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA, funcsA, nFuncsA); if (!shading->init(dict)) { delete shading; return NULL; } return shading; err2: obj2.free(); err1: obj1.free(); return NULL; } GfxShading *GfxFunctionShading::copy() { return new GfxFunctionShading(this); } void GfxFunctionShading::getColor(double x, double y, GfxColor *color) { double in[2], out[gfxColorMaxComps]; int i; // NB: there can be one function with n outputs or n functions with // one output each (where n = number of color components) for (i = 0; i < gfxColorMaxComps; ++i) { out[i] = 0; } in[0] = x; in[1] = y; for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(in, &out[i]); } for (i = 0; i < gfxColorMaxComps; ++i) { color->c[i] = dblToCol(out[i]); } } //------------------------------------------------------------------------ // GfxAxialShading //------------------------------------------------------------------------ GfxAxialShading::GfxAxialShading(double x0A, double y0A, double x1A, double y1A, double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A): GfxShading(2) { int i; x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; t0 = t0A; t1 = t1A; nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } extend0 = extend0A; extend1 = extend1A; } GfxAxialShading::GfxAxialShading(GfxAxialShading *shading): GfxShading(shading) { int i; x0 = shading->x0; y0 = shading->y0; x1 = shading->x1; y1 = shading->y1; t0 = shading->t0; t1 = shading->t1; nFuncs = shading->nFuncs; for (i = 0; i < nFuncs; ++i) { funcs[i] = shading->funcs[i]->copy(); } extend0 = shading->extend0; extend1 = shading->extend1; } GfxAxialShading::~GfxAxialShading() { int i; for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxAxialShading *GfxAxialShading::parse(Dict *dict) { GfxAxialShading *shading; double x0A, y0A, x1A, y1A; double t0A, t1A; Function *funcsA[gfxColorMaxComps]; int nFuncsA; GBool extend0A, extend1A; Object obj1, obj2; int i; x0A = y0A = x1A = y1A = 0; if (dict->lookup("Coords", &obj1)->isArray() && obj1.arrayGetLength() == 4) { x0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); y0A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); x1A = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); y1A = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); } else { error(errSyntaxError, -1, "Missing or invalid Coords in shading dictionary"); goto err1; } obj1.free(); t0A = 0; t1A = 1; if (dict->lookup("Domain", &obj1)->isArray() && obj1.arrayGetLength() == 2) { t0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); t1A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); } obj1.free(); dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); if (nFuncsA > gfxColorMaxComps) { error(errSyntaxError, -1, "Invalid Function array in shading dictionary"); goto err1; } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { obj1.free(); obj2.free(); goto err1; } obj2.free(); } } else { nFuncsA = 1; if (!(funcsA[0] = Function::parse(&obj1))) { obj1.free(); goto err1; } } obj1.free(); extend0A = extend1A = gFalse; if (dict->lookup("Extend", &obj1)->isArray() && obj1.arrayGetLength() == 2) { extend0A = obj1.arrayGet(0, &obj2)->getBool(); obj2.free(); extend1A = obj1.arrayGet(1, &obj2)->getBool(); obj2.free(); } obj1.free(); shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A); if (!shading->init(dict)) { delete shading; return NULL; } return shading; err1: return NULL; } GfxShading *GfxAxialShading::copy() { return new GfxAxialShading(this); } void GfxAxialShading::getColor(double t, GfxColor *color) { double out[gfxColorMaxComps]; int i; // NB: there can be one function with n outputs or n functions with // one output each (where n = number of color components) for (i = 0; i < gfxColorMaxComps; ++i) { out[i] = 0; } for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(&t, &out[i]); } for (i = 0; i < gfxColorMaxComps; ++i) { color->c[i] = dblToCol(out[i]); } } //------------------------------------------------------------------------ // GfxRadialShading //------------------------------------------------------------------------ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A, double x1A, double y1A, double r1A, double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A): GfxShading(3) { int i; x0 = x0A; y0 = y0A; r0 = r0A; x1 = x1A; y1 = y1A; r1 = r1A; t0 = t0A; t1 = t1A; nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } extend0 = extend0A; extend1 = extend1A; } GfxRadialShading::GfxRadialShading(GfxRadialShading *shading): GfxShading(shading) { int i; x0 = shading->x0; y0 = shading->y0; r0 = shading->r0; x1 = shading->x1; y1 = shading->y1; r1 = shading->r1; t0 = shading->t0; t1 = shading->t1; nFuncs = shading->nFuncs; for (i = 0; i < nFuncs; ++i) { funcs[i] = shading->funcs[i]->copy(); } extend0 = shading->extend0; extend1 = shading->extend1; } GfxRadialShading::~GfxRadialShading() { int i; for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxRadialShading *GfxRadialShading::parse(Dict *dict) { GfxRadialShading *shading; double x0A, y0A, r0A, x1A, y1A, r1A; double t0A, t1A; Function *funcsA[gfxColorMaxComps]; int nFuncsA; GBool extend0A, extend1A; Object obj1, obj2; int i; x0A = y0A = r0A = x1A = y1A = r1A = 0; if (dict->lookup("Coords", &obj1)->isArray() && obj1.arrayGetLength() == 6) { x0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); y0A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); r0A = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); x1A = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); y1A = obj1.arrayGet(4, &obj2)->getNum(); obj2.free(); r1A = obj1.arrayGet(5, &obj2)->getNum(); obj2.free(); } else { error(errSyntaxError, -1, "Missing or invalid Coords in shading dictionary"); goto err1; } obj1.free(); t0A = 0; t1A = 1; if (dict->lookup("Domain", &obj1)->isArray() && obj1.arrayGetLength() == 2) { t0A = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); t1A = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); } obj1.free(); dict->lookup("Function", &obj1); if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); if (nFuncsA > gfxColorMaxComps) { error(errSyntaxError, -1, "Invalid Function array in shading dictionary"); goto err1; } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { obj1.free(); obj2.free(); goto err1; } obj2.free(); } } else { nFuncsA = 1; if (!(funcsA[0] = Function::parse(&obj1))) { obj1.free(); goto err1; } } obj1.free(); extend0A = extend1A = gFalse; if (dict->lookup("Extend", &obj1)->isArray() && obj1.arrayGetLength() == 2) { extend0A = obj1.arrayGet(0, &obj2)->getBool(); obj2.free(); extend1A = obj1.arrayGet(1, &obj2)->getBool(); obj2.free(); } obj1.free(); shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A, funcsA, nFuncsA, extend0A, extend1A); if (!shading->init(dict)) { delete shading; return NULL; } return shading; err1: return NULL; } GfxShading *GfxRadialShading::copy() { return new GfxRadialShading(this); } void GfxRadialShading::getColor(double t, GfxColor *color) { double out[gfxColorMaxComps]; int i; // NB: there can be one function with n outputs or n functions with // one output each (where n = number of color components) for (i = 0; i < gfxColorMaxComps; ++i) { out[i] = 0; } for (i = 0; i < nFuncs; ++i) { funcs[i]->transform(&t, &out[i]); } for (i = 0; i < gfxColorMaxComps; ++i) { color->c[i] = dblToCol(out[i]); } } //------------------------------------------------------------------------ // GfxShadingBitBuf //------------------------------------------------------------------------ class GfxShadingBitBuf { public: GfxShadingBitBuf(Stream *strA); ~GfxShadingBitBuf(); GBool getBits(int n, Guint *val); void flushBits(); private: Stream *str; int bitBuf; int nBits; }; GfxShadingBitBuf::GfxShadingBitBuf(Stream *strA) { str = strA; str->reset(); bitBuf = 0; nBits = 0; } GfxShadingBitBuf::~GfxShadingBitBuf() { str->close(); } GBool GfxShadingBitBuf::getBits(int n, Guint *val) { int x; if (nBits >= n) { x = (bitBuf >> (nBits - n)) & ((1 << n) - 1); nBits -= n; } else { x = 0; if (nBits > 0) { x = bitBuf & ((1 << nBits) - 1); n -= nBits; nBits = 0; } while (n > 0) { if ((bitBuf = str->getChar()) == EOF) { nBits = 0; return gFalse; } if (n >= 8) { x = (x << 8) | bitBuf; n -= 8; } else { x = (x << n) | (bitBuf >> (8 - n)); nBits = 8 - n; n = 0; } } } *val = x; return gTrue; } void GfxShadingBitBuf::flushBits() { bitBuf = 0; nBits = 0; } //------------------------------------------------------------------------ // GfxGouraudTriangleShading //------------------------------------------------------------------------ GfxGouraudTriangleShading::GfxGouraudTriangleShading( int typeA, GfxGouraudVertex *verticesA, int nVerticesA, int (*trianglesA)[3], int nTrianglesA, Function **funcsA, int nFuncsA): GfxShading(typeA) { int i; vertices = verticesA; nVertices = nVerticesA; triangles = trianglesA; nTriangles = nTrianglesA; nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } } GfxGouraudTriangleShading::GfxGouraudTriangleShading( GfxGouraudTriangleShading *shading): GfxShading(shading) { int i; nVertices = shading->nVertices; vertices = (GfxGouraudVertex *)gmallocn(nVertices, sizeof(GfxGouraudVertex)); memcpy(vertices, shading->vertices, nVertices * sizeof(GfxGouraudVertex)); nTriangles = shading->nTriangles; triangles = (int (*)[3])gmallocn(nTriangles * 3, sizeof(int)); memcpy(triangles, shading->triangles, nTriangles * 3 * sizeof(int)); nFuncs = shading->nFuncs; for (i = 0; i < nFuncs; ++i) { funcs[i] = shading->funcs[i]->copy(); } } GfxGouraudTriangleShading::~GfxGouraudTriangleShading() { int i; gfree(vertices); gfree(triangles); for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxGouraudTriangleShading *GfxGouraudTriangleShading::parse(int typeA, Dict *dict, Stream *str) { GfxGouraudTriangleShading *shading; Function *funcsA[gfxColorMaxComps]; int nFuncsA; int coordBits, compBits, flagBits, vertsPerRow, nRows; double xMin, xMax, yMin, yMax; double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; double xMul, yMul; double cMul[gfxColorMaxComps]; GfxGouraudVertex *verticesA; int (*trianglesA)[3]; int nComps, nVerticesA, nTrianglesA, vertSize, triSize; Guint x, y, flag; Guint c[gfxColorMaxComps]; GfxShadingBitBuf *bitBuf; Object obj1, obj2; int i, j, k, state; if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { coordBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerCoordinate in shading dictionary"); goto err2; } obj1.free(); if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { compBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerComponent in shading dictionary"); goto err2; } obj1.free(); flagBits = vertsPerRow = 0; // make gcc happy if (typeA == 4) { if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { flagBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerFlag in shading dictionary"); goto err2; } obj1.free(); } else { if (dict->lookup("VerticesPerRow", &obj1)->isInt()) { vertsPerRow = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid VerticesPerRow in shading dictionary"); goto err2; } obj1.free(); } if (dict->lookup("Decode", &obj1)->isArray() && obj1.arrayGetLength() >= 6) { xMin = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); xMax = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); yMin = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); yMax = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); obj2.free(); cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); obj2.free(); cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); } nComps = i; } else { error(errSyntaxError, -1, "Missing or invalid Decode array in shading dictionary"); goto err2; } obj1.free(); if (!dict->lookup("Function", &obj1)->isNull()) { if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); if (nFuncsA > gfxColorMaxComps) { error(errSyntaxError, -1, "Invalid Function array in shading dictionary"); goto err1; } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { obj1.free(); obj2.free(); goto err1; } obj2.free(); } } else { nFuncsA = 1; if (!(funcsA[0] = Function::parse(&obj1))) { obj1.free(); goto err1; } } } else { nFuncsA = 0; } obj1.free(); nVerticesA = nTrianglesA = 0; verticesA = NULL; trianglesA = NULL; vertSize = triSize = 0; state = 0; flag = 0; // make gcc happy bitBuf = new GfxShadingBitBuf(str); while (1) { if (typeA == 4) { if (!bitBuf->getBits(flagBits, &flag)) { break; } } if (!bitBuf->getBits(coordBits, &x) || !bitBuf->getBits(coordBits, &y)) { break; } for (i = 0; i < nComps; ++i) { if (!bitBuf->getBits(compBits, &c[i])) { break; } } if (i < nComps) { break; } if (nVerticesA == vertSize) { vertSize = (vertSize == 0) ? 16 : 2 * vertSize; verticesA = (GfxGouraudVertex *) greallocn(verticesA, vertSize, sizeof(GfxGouraudVertex)); } verticesA[nVerticesA].x = xMin + xMul * (double)x; verticesA[nVerticesA].y = yMin + yMul * (double)y; for (i = 0; i < nComps; ++i) { verticesA[nVerticesA].color.c[i] = dblToCol(cMin[i] + cMul[i] * (double)c[i]); } ++nVerticesA; bitBuf->flushBits(); if (typeA == 4) { if (state == 0 || state == 1) { ++state; } else if (state == 2 || flag > 0) { if (nTrianglesA == triSize) { triSize = (triSize == 0) ? 16 : 2 * triSize; trianglesA = (int (*)[3]) greallocn(trianglesA, triSize * 3, sizeof(int)); } if (state == 2) { trianglesA[nTrianglesA][0] = nVerticesA - 3; trianglesA[nTrianglesA][1] = nVerticesA - 2; trianglesA[nTrianglesA][2] = nVerticesA - 1; ++state; } else if (flag == 1) { trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][1]; trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; trianglesA[nTrianglesA][2] = nVerticesA - 1; } else { // flag == 2 trianglesA[nTrianglesA][0] = trianglesA[nTrianglesA - 1][0]; trianglesA[nTrianglesA][1] = trianglesA[nTrianglesA - 1][2]; trianglesA[nTrianglesA][2] = nVerticesA - 1; } ++nTrianglesA; } else { // state == 3 && flag == 0 state = 1; } } } delete bitBuf; if (typeA == 5) { nRows = nVerticesA / vertsPerRow; nTrianglesA = (nRows - 1) * 2 * (vertsPerRow - 1); trianglesA = (int (*)[3])gmallocn(nTrianglesA * 3, sizeof(int)); k = 0; for (i = 0; i < nRows - 1; ++i) { for (j = 0; j < vertsPerRow - 1; ++j) { trianglesA[k][0] = i * vertsPerRow + j; trianglesA[k][1] = i * vertsPerRow + j+1; trianglesA[k][2] = (i+1) * vertsPerRow + j; ++k; trianglesA[k][0] = i * vertsPerRow + j+1; trianglesA[k][1] = (i+1) * vertsPerRow + j; trianglesA[k][2] = (i+1) * vertsPerRow + j+1; ++k; } } } shading = new GfxGouraudTriangleShading(typeA, verticesA, nVerticesA, trianglesA, nTrianglesA, funcsA, nFuncsA); if (!shading->init(dict)) { delete shading; return NULL; } return shading; err2: obj1.free(); err1: return NULL; } GfxShading *GfxGouraudTriangleShading::copy() { return new GfxGouraudTriangleShading(this); } void GfxGouraudTriangleShading::getTriangle( int i, double *x0, double *y0, GfxColor *color0, double *x1, double *y1, GfxColor *color1, double *x2, double *y2, GfxColor *color2) { double in; double out[gfxColorMaxComps]; int v, j; v = triangles[i][0]; *x0 = vertices[v].x; *y0 = vertices[v].y; if (nFuncs > 0) { in = colToDbl(vertices[v].color.c[0]); for (j = 0; j < nFuncs; ++j) { funcs[j]->transform(&in, &out[j]); } for (j = 0; j < gfxColorMaxComps; ++j) { color0->c[j] = dblToCol(out[j]); } } else { *color0 = vertices[v].color; } v = triangles[i][1]; *x1 = vertices[v].x; *y1 = vertices[v].y; if (nFuncs > 0) { in = colToDbl(vertices[v].color.c[0]); for (j = 0; j < nFuncs; ++j) { funcs[j]->transform(&in, &out[j]); } for (j = 0; j < gfxColorMaxComps; ++j) { color1->c[j] = dblToCol(out[j]); } } else { *color1 = vertices[v].color; } v = triangles[i][2]; *x2 = vertices[v].x; *y2 = vertices[v].y; if (nFuncs > 0) { in = colToDbl(vertices[v].color.c[0]); for (j = 0; j < nFuncs; ++j) { funcs[j]->transform(&in, &out[j]); } for (j = 0; j < gfxColorMaxComps; ++j) { color2->c[j] = dblToCol(out[j]); } } else { *color2 = vertices[v].color; } } //------------------------------------------------------------------------ // GfxPatchMeshShading //------------------------------------------------------------------------ GfxPatchMeshShading::GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, Function **funcsA, int nFuncsA): GfxShading(typeA) { int i; patches = patchesA; nPatches = nPatchesA; nFuncs = nFuncsA; for (i = 0; i < nFuncs; ++i) { funcs[i] = funcsA[i]; } } GfxPatchMeshShading::GfxPatchMeshShading(GfxPatchMeshShading *shading): GfxShading(shading) { int i; nPatches = shading->nPatches; patches = (GfxPatch *)gmallocn(nPatches, sizeof(GfxPatch)); memcpy(patches, shading->patches, nPatches * sizeof(GfxPatch)); nFuncs = shading->nFuncs; for (i = 0; i < nFuncs; ++i) { funcs[i] = shading->funcs[i]->copy(); } } GfxPatchMeshShading::~GfxPatchMeshShading() { int i; gfree(patches); for (i = 0; i < nFuncs; ++i) { delete funcs[i]; } } GfxPatchMeshShading *GfxPatchMeshShading::parse(int typeA, Dict *dict, Stream *str) { GfxPatchMeshShading *shading; Function *funcsA[gfxColorMaxComps]; int nFuncsA; int coordBits, compBits, flagBits; double xMin, xMax, yMin, yMax; double cMin[gfxColorMaxComps], cMax[gfxColorMaxComps]; double xMul, yMul; double cMul[gfxColorMaxComps]; GfxPatch *patchesA, *p; int nComps, nPatchesA, patchesSize, nPts, nColors; Guint flag; double x[16], y[16]; Guint xi, yi; GfxColorComp c[4][gfxColorMaxComps]; Guint ci; GfxShadingBitBuf *bitBuf; Object obj1, obj2; int i, j; if (dict->lookup("BitsPerCoordinate", &obj1)->isInt()) { coordBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerCoordinate in shading dictionary"); goto err2; } obj1.free(); if (dict->lookup("BitsPerComponent", &obj1)->isInt()) { compBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerComponent in shading dictionary"); goto err2; } obj1.free(); if (dict->lookup("BitsPerFlag", &obj1)->isInt()) { flagBits = obj1.getInt(); } else { error(errSyntaxError, -1, "Missing or invalid BitsPerFlag in shading dictionary"); goto err2; } obj1.free(); if (dict->lookup("Decode", &obj1)->isArray() && obj1.arrayGetLength() >= 6) { xMin = obj1.arrayGet(0, &obj2)->getNum(); obj2.free(); xMax = obj1.arrayGet(1, &obj2)->getNum(); obj2.free(); xMul = (xMax - xMin) / (pow(2.0, coordBits) - 1); yMin = obj1.arrayGet(2, &obj2)->getNum(); obj2.free(); yMax = obj1.arrayGet(3, &obj2)->getNum(); obj2.free(); yMul = (yMax - yMin) / (pow(2.0, coordBits) - 1); for (i = 0; 5 + 2*i < obj1.arrayGetLength() && i < gfxColorMaxComps; ++i) { cMin[i] = obj1.arrayGet(4 + 2*i, &obj2)->getNum(); obj2.free(); cMax[i] = obj1.arrayGet(5 + 2*i, &obj2)->getNum(); obj2.free(); cMul[i] = (cMax[i] - cMin[i]) / (double)((1 << compBits) - 1); } nComps = i; } else { error(errSyntaxError, -1, "Missing or invalid Decode array in shading dictionary"); goto err2; } obj1.free(); if (!dict->lookup("Function", &obj1)->isNull()) { if (obj1.isArray()) { nFuncsA = obj1.arrayGetLength(); if (nFuncsA > gfxColorMaxComps) { error(errSyntaxError, -1, "Invalid Function array in shading dictionary"); goto err1; } for (i = 0; i < nFuncsA; ++i) { obj1.arrayGet(i, &obj2); if (!(funcsA[i] = Function::parse(&obj2))) { obj1.free(); obj2.free(); goto err1; } obj2.free(); } } else { nFuncsA = 1; if (!(funcsA[0] = Function::parse(&obj1))) { obj1.free(); goto err1; } } } else { nFuncsA = 0; } obj1.free(); nPatchesA = 0; patchesA = NULL; patchesSize = 0; bitBuf = new GfxShadingBitBuf(str); while (1) { if (!bitBuf->getBits(flagBits, &flag)) { break; } if (typeA == 6) { switch (flag) { case 0: nPts = 12; nColors = 4; break; case 1: case 2: case 3: default: nPts = 8; nColors = 2; break; } } else { switch (flag) { case 0: nPts = 16; nColors = 4; break; case 1: case 2: case 3: default: nPts = 12; nColors = 2; break; } } for (i = 0; i < nPts; ++i) { if (!bitBuf->getBits(coordBits, &xi) || !bitBuf->getBits(coordBits, &yi)) { break; } x[i] = xMin + xMul * (double)xi; y[i] = yMin + yMul * (double)yi; } if (i < nPts) { break; } for (i = 0; i < nColors; ++i) { for (j = 0; j < nComps; ++j) { if (!bitBuf->getBits(compBits, &ci)) { break; } c[i][j] = dblToCol(cMin[j] + cMul[j] * (double)ci); } if (j < nComps) { break; } } if (i < nColors) { break; } if (nPatchesA == patchesSize) { patchesSize = (patchesSize == 0) ? 16 : 2 * patchesSize; patchesA = (GfxPatch *)greallocn(patchesA, patchesSize, sizeof(GfxPatch)); } p = &patchesA[nPatchesA]; if (typeA == 6) { switch (flag) { case 0: p->x[0][0] = x[0]; p->y[0][0] = y[0]; p->x[0][1] = x[1]; p->y[0][1] = y[1]; p->x[0][2] = x[2]; p->y[0][2] = y[2]; p->x[0][3] = x[3]; p->y[0][3] = y[3]; p->x[1][3] = x[4]; p->y[1][3] = y[4]; p->x[2][3] = x[5]; p->y[2][3] = y[5]; p->x[3][3] = x[6]; p->y[3][3] = y[6]; p->x[3][2] = x[7]; p->y[3][2] = y[7]; p->x[3][1] = x[8]; p->y[3][1] = y[8]; p->x[3][0] = x[9]; p->y[3][0] = y[9]; p->x[2][0] = x[10]; p->y[2][0] = y[10]; p->x[1][0] = x[11]; p->y[1][0] = y[11]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = c[0][j]; p->color[0][1].c[j] = c[1][j]; p->color[1][1].c[j] = c[2][j]; p->color[1][0].c[j] = c[3][j]; } break; case 1: p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; case 2: p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; case 3: p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; for (j = 0; j < nComps; ++j) { p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; } } else { switch (flag) { case 0: p->x[0][0] = x[0]; p->y[0][0] = y[0]; p->x[0][1] = x[1]; p->y[0][1] = y[1]; p->x[0][2] = x[2]; p->y[0][2] = y[2]; p->x[0][3] = x[3]; p->y[0][3] = y[3]; p->x[1][3] = x[4]; p->y[1][3] = y[4]; p->x[2][3] = x[5]; p->y[2][3] = y[5]; p->x[3][3] = x[6]; p->y[3][3] = y[6]; p->x[3][2] = x[7]; p->y[3][2] = y[7]; p->x[3][1] = x[8]; p->y[3][1] = y[8]; p->x[3][0] = x[9]; p->y[3][0] = y[9]; p->x[2][0] = x[10]; p->y[2][0] = y[10]; p->x[1][0] = x[11]; p->y[1][0] = y[11]; p->x[1][1] = x[12]; p->y[1][1] = y[12]; p->x[1][2] = x[13]; p->y[1][2] = y[13]; p->x[2][2] = x[14]; p->y[2][2] = y[14]; p->x[2][1] = x[15]; p->y[2][1] = y[15]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = c[0][j]; p->color[0][1].c[j] = c[1][j]; p->color[1][1].c[j] = c[2][j]; p->color[1][0].c[j] = c[3][j]; } break; case 1: p->x[0][0] = patchesA[nPatchesA-1].x[0][3]; p->y[0][0] = patchesA[nPatchesA-1].y[0][3]; p->x[0][1] = patchesA[nPatchesA-1].x[1][3]; p->y[0][1] = patchesA[nPatchesA-1].y[1][3]; p->x[0][2] = patchesA[nPatchesA-1].x[2][3]; p->y[0][2] = patchesA[nPatchesA-1].y[2][3]; p->x[0][3] = patchesA[nPatchesA-1].x[3][3]; p->y[0][3] = patchesA[nPatchesA-1].y[3][3]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; p->x[1][1] = x[8]; p->y[1][1] = y[8]; p->x[1][2] = x[9]; p->y[1][2] = y[9]; p->x[2][2] = x[10]; p->y[2][2] = y[10]; p->x[2][1] = x[11]; p->y[2][1] = y[11]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = patchesA[nPatchesA-1].color[0][1].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; case 2: p->x[0][0] = patchesA[nPatchesA-1].x[3][3]; p->y[0][0] = patchesA[nPatchesA-1].y[3][3]; p->x[0][1] = patchesA[nPatchesA-1].x[3][2]; p->y[0][1] = patchesA[nPatchesA-1].y[3][2]; p->x[0][2] = patchesA[nPatchesA-1].x[3][1]; p->y[0][2] = patchesA[nPatchesA-1].y[3][1]; p->x[0][3] = patchesA[nPatchesA-1].x[3][0]; p->y[0][3] = patchesA[nPatchesA-1].y[3][0]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; p->x[1][1] = x[8]; p->y[1][1] = y[8]; p->x[1][2] = x[9]; p->y[1][2] = y[9]; p->x[2][2] = x[10]; p->y[2][2] = y[10]; p->x[2][1] = x[11]; p->y[2][1] = y[11]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][1].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; case 3: p->x[0][0] = patchesA[nPatchesA-1].x[3][0]; p->y[0][0] = patchesA[nPatchesA-1].y[3][0]; p->x[0][1] = patchesA[nPatchesA-1].x[2][0]; p->y[0][1] = patchesA[nPatchesA-1].y[2][0]; p->x[0][2] = patchesA[nPatchesA-1].x[1][0]; p->y[0][2] = patchesA[nPatchesA-1].y[1][0]; p->x[0][3] = patchesA[nPatchesA-1].x[0][0]; p->y[0][3] = patchesA[nPatchesA-1].y[0][0]; p->x[1][3] = x[0]; p->y[1][3] = y[0]; p->x[2][3] = x[1]; p->y[2][3] = y[1]; p->x[3][3] = x[2]; p->y[3][3] = y[2]; p->x[3][2] = x[3]; p->y[3][2] = y[3]; p->x[3][1] = x[4]; p->y[3][1] = y[4]; p->x[3][0] = x[5]; p->y[3][0] = y[5]; p->x[2][0] = x[6]; p->y[2][0] = y[6]; p->x[1][0] = x[7]; p->y[1][0] = y[7]; p->x[1][1] = x[8]; p->y[1][1] = y[8]; p->x[1][2] = x[9]; p->y[1][2] = y[9]; p->x[2][2] = x[10]; p->y[2][2] = y[10]; p->x[2][1] = x[11]; p->y[2][1] = y[11]; for (j = 0; j < nComps; ++j) { p->color[0][0].c[j] = patchesA[nPatchesA-1].color[1][0].c[j]; p->color[0][1].c[j] = patchesA[nPatchesA-1].color[0][0].c[j]; p->color[1][1].c[j] = c[0][j]; p->color[1][0].c[j] = c[1][j]; } break; } } ++nPatchesA; bitBuf->flushBits(); } delete bitBuf; if (typeA == 6) { for (i = 0; i < nPatchesA; ++i) { p = &patchesA[i]; p->x[1][1] = (-4 * p->x[0][0] +6 * (p->x[0][1] + p->x[1][0]) -2 * (p->x[0][3] + p->x[3][0]) +3 * (p->x[3][1] + p->x[1][3]) - p->x[3][3]) / 9; p->y[1][1] = (-4 * p->y[0][0] +6 * (p->y[0][1] + p->y[1][0]) -2 * (p->y[0][3] + p->y[3][0]) +3 * (p->y[3][1] + p->y[1][3]) - p->y[3][3]) / 9; p->x[1][2] = (-4 * p->x[0][3] +6 * (p->x[0][2] + p->x[1][3]) -2 * (p->x[0][0] + p->x[3][3]) +3 * (p->x[3][2] + p->x[1][0]) - p->x[3][0]) / 9; p->y[1][2] = (-4 * p->y[0][3] +6 * (p->y[0][2] + p->y[1][3]) -2 * (p->y[0][0] + p->y[3][3]) +3 * (p->y[3][2] + p->y[1][0]) - p->y[3][0]) / 9; p->x[2][1] = (-4 * p->x[3][0] +6 * (p->x[3][1] + p->x[2][0]) -2 * (p->x[3][3] + p->x[0][0]) +3 * (p->x[0][1] + p->x[2][3]) - p->x[0][3]) / 9; p->y[2][1] = (-4 * p->y[3][0] +6 * (p->y[3][1] + p->y[2][0]) -2 * (p->y[3][3] + p->y[0][0]) +3 * (p->y[0][1] + p->y[2][3]) - p->y[0][3]) / 9; p->x[2][2] = (-4 * p->x[3][3] +6 * (p->x[3][2] + p->x[2][3]) -2 * (p->x[3][0] + p->x[0][3]) +3 * (p->x[0][2] + p->x[2][0]) - p->x[0][0]) / 9; p->y[2][2] = (-4 * p->y[3][3] +6 * (p->y[3][2] + p->y[2][3]) -2 * (p->y[3][0] + p->y[0][3]) +3 * (p->y[0][2] + p->y[2][0]) - p->y[0][0]) / 9; } } shading = new GfxPatchMeshShading(typeA, patchesA, nPatchesA, funcsA, nFuncsA); if (!shading->init(dict)) { delete shading; return NULL; } return shading; err2: obj1.free(); err1: return NULL; } GfxShading *GfxPatchMeshShading::copy() { return new GfxPatchMeshShading(this); } //------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA) { GfxIndexedColorSpace *indexedCS; GfxSeparationColorSpace *sepCS; int maxPixel, indexHigh; Guchar *indexedLookup; Function *sepFunc; Object obj; double x[gfxColorMaxComps]; double y[gfxColorMaxComps]; int i, j, k; ok = gTrue; // bits per component and color space bits = bitsA; maxPixel = (1 << bits) - 1; colorSpace = colorSpaceA; // initialize for (k = 0; k < gfxColorMaxComps; ++k) { lookup[k] = NULL; lookup2[k] = NULL; } // get decode map if (decode->isNull()) { nComps = colorSpace->getNComps(); colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel); } else if (decode->isArray()) { nComps = decode->arrayGetLength() / 2; if (nComps < colorSpace->getNComps()) { goto err1; } if (nComps > colorSpace->getNComps()) { error(errSyntaxWarning, -1, "Too many elements in Decode array"); nComps = colorSpace->getNComps(); } for (i = 0; i < nComps; ++i) { decode->arrayGet(2*i, &obj); if (!obj.isNum()) { goto err2; } decodeLow[i] = obj.getNum(); obj.free(); decode->arrayGet(2*i+1, &obj); if (!obj.isNum()) { goto err2; } decodeRange[i] = obj.getNum() - decodeLow[i]; obj.free(); } } else { goto err1; } // Construct a lookup table -- this stores pre-computed decoded // values for each component, i.e., the result of applying the // decode mapping to each possible image pixel component value. for (k = 0; k < nComps; ++k) { lookup[k] = (GfxColorComp *)gmallocn(maxPixel + 1, sizeof(GfxColorComp)); for (i = 0; i <= maxPixel; ++i) { lookup[k][i] = dblToCol(decodeLow[k] + (i * decodeRange[k]) / maxPixel); } } // Optimization: for Indexed and Separation color spaces (which have // only one component), we pre-compute a second lookup table with // color values colorSpace2 = NULL; nComps2 = 0; if (colorSpace->getMode() == csIndexed) { // Note that indexHigh may not be the same as maxPixel -- // Distiller will remove unused palette entries, resulting in // indexHigh < maxPixel. indexedCS = (GfxIndexedColorSpace *)colorSpace; colorSpace2 = indexedCS->getBase(); indexHigh = indexedCS->getIndexHigh(); nComps2 = colorSpace2->getNComps(); indexedLookup = indexedCS->getLookup(); colorSpace2->getDefaultRanges(x, y, indexHigh); for (k = 0; k < nComps2; ++k) { lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1, sizeof(GfxColorComp)); } for (i = 0; i <= maxPixel; ++i) { j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); if (j < 0) { j = 0; } else if (j > indexHigh) { j = indexHigh; } for (k = 0; k < nComps2; ++k) { lookup2[k][i] = dblToCol(x[k] + (indexedLookup[j*nComps2 + k] / 255.0) * y[k]); } } } else if (colorSpace->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)colorSpace; colorSpace2 = sepCS->getAlt(); nComps2 = colorSpace2->getNComps(); sepFunc = sepCS->getFunc(); for (k = 0; k < nComps2; ++k) { lookup2[k] = (GfxColorComp *)gmallocn(maxPixel + 1, sizeof(GfxColorComp)); } for (i = 0; i <= maxPixel; ++i) { x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel; sepFunc->transform(x, y); for (k = 0; k < nComps2; ++k) { lookup2[k][i] = dblToCol(y[k]); } } } return; err2: obj.free(); err1: ok = gFalse; } GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { int n, i, k; colorSpace = colorMap->colorSpace->copy(); bits = colorMap->bits; nComps = colorMap->nComps; nComps2 = colorMap->nComps2; colorSpace2 = NULL; for (k = 0; k < gfxColorMaxComps; ++k) { lookup[k] = NULL; lookup2[k] = NULL; } n = 1 << bits; for (k = 0; k < nComps; ++k) { lookup[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); memcpy(lookup[k], colorMap->lookup[k], n * sizeof(GfxColorComp)); } if (colorSpace->getMode() == csIndexed) { colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); for (k = 0; k < nComps2; ++k) { lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp)); } } else if (colorSpace->getMode() == csSeparation) { colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); for (k = 0; k < nComps2; ++k) { lookup2[k] = (GfxColorComp *)gmallocn(n, sizeof(GfxColorComp)); memcpy(lookup2[k], colorMap->lookup2[k], n * sizeof(GfxColorComp)); } } for (i = 0; i < nComps; ++i) { decodeLow[i] = colorMap->decodeLow[i]; decodeRange[i] = colorMap->decodeRange[i]; } ok = gTrue; } GfxImageColorMap::~GfxImageColorMap() { int i; delete colorSpace; for (i = 0; i < gfxColorMaxComps; ++i) { gfree(lookup[i]); gfree(lookup2[i]); } } void GfxImageColorMap::getGray(Guchar *x, GfxGray *gray) { GfxColor color; int i; if (colorSpace2) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][x[0]]; } colorSpace2->getGray(&color, gray); } else { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][x[i]]; } colorSpace->getGray(&color, gray); } } void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) { GfxColor color; int i; if (colorSpace2) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][x[0]]; } colorSpace2->getRGB(&color, rgb); } else { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][x[i]]; } colorSpace->getRGB(&color, rgb); } } void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) { GfxColor color; int i; if (colorSpace2) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][x[0]]; } colorSpace2->getCMYK(&color, cmyk); } else { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][x[i]]; } colorSpace->getCMYK(&color, cmyk); } } void GfxImageColorMap::getColor(Guchar *x, GfxColor *color) { int maxPixel, i; maxPixel = (1 << bits) - 1; for (i = 0; i < nComps; ++i) { color->c[i] = dblToCol(decodeLow[i] + (x[i] * decodeRange[i]) / maxPixel); } } void GfxImageColorMap::getGrayByteLine(Guchar *in, Guchar *out, int n) { GfxColor color; GfxGray gray; int i, j; if (colorSpace2) { for (j = 0; j < n; ++j) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][in[j]]; } colorSpace2->getGray(&color, &gray); out[j] = colToByte(gray); } } else { for (j = 0; j < n; ++j) { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][in[j * nComps + i]]; } colorSpace->getGray(&color, &gray); out[j] = colToByte(gray); } } } void GfxImageColorMap::getRGBByteLine(Guchar *in, Guchar *out, int n) { GfxColor color; GfxRGB rgb; int i, j; if (colorSpace2) { for (j = 0; j < n; ++j) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][in[j]]; } colorSpace2->getRGB(&color, &rgb); out[j*3] = colToByte(rgb.r); out[j*3 + 1] = colToByte(rgb.g); out[j*3 + 2] = colToByte(rgb.b); } } else { for (j = 0; j < n; ++j) { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][in[j * nComps + i]]; } colorSpace->getRGB(&color, &rgb); out[j*3] = colToByte(rgb.r); out[j*3 + 1] = colToByte(rgb.g); out[j*3 + 2] = colToByte(rgb.b); } } } void GfxImageColorMap::getCMYKByteLine(Guchar *in, Guchar *out, int n) { GfxColor color; GfxCMYK cmyk; int i, j; if (colorSpace2) { for (j = 0; j < n; ++j) { for (i = 0; i < nComps2; ++i) { color.c[i] = lookup2[i][in[j]]; } colorSpace2->getCMYK(&color, &cmyk); out[j*4] = colToByte(cmyk.c); out[j*4 + 1] = colToByte(cmyk.m); out[j*4 + 2] = colToByte(cmyk.y); out[j*4 + 3] = colToByte(cmyk.k); } } else { for (j = 0; j < n; ++j) { for (i = 0; i < nComps; ++i) { color.c[i] = lookup[i][in[j * nComps + i]]; } colorSpace->getCMYK(&color, &cmyk); out[j*4] = colToByte(cmyk.c); out[j*4 + 1] = colToByte(cmyk.m); out[j*4 + 2] = colToByte(cmyk.y); out[j*4 + 3] = colToByte(cmyk.k); } } } //------------------------------------------------------------------------ // GfxSubpath and GfxPath //------------------------------------------------------------------------ GfxSubpath::GfxSubpath(double x1, double y1) { size = 16; x = (double *)gmallocn(size, sizeof(double)); y = (double *)gmallocn(size, sizeof(double)); curve = (GBool *)gmallocn(size, sizeof(GBool)); n = 1; x[0] = x1; y[0] = y1; curve[0] = gFalse; closed = gFalse; } GfxSubpath::~GfxSubpath() { gfree(x); gfree(y); gfree(curve); } // Used for copy(). GfxSubpath::GfxSubpath(GfxSubpath *subpath) { size = subpath->size; n = subpath->n; x = (double *)gmallocn(size, sizeof(double)); y = (double *)gmallocn(size, sizeof(double)); curve = (GBool *)gmallocn(size, sizeof(GBool)); memcpy(x, subpath->x, n * sizeof(double)); memcpy(y, subpath->y, n * sizeof(double)); memcpy(curve, subpath->curve, n * sizeof(GBool)); closed = subpath->closed; } void GfxSubpath::lineTo(double x1, double y1) { if (n >= size) { size *= 2; x = (double *)greallocn(x, size, sizeof(double)); y = (double *)greallocn(y, size, sizeof(double)); curve = (GBool *)greallocn(curve, size, sizeof(GBool)); } x[n] = x1; y[n] = y1; curve[n] = gFalse; ++n; } void GfxSubpath::curveTo(double x1, double y1, double x2, double y2, double x3, double y3) { if (n+3 > size) { size *= 2; x = (double *)greallocn(x, size, sizeof(double)); y = (double *)greallocn(y, size, sizeof(double)); curve = (GBool *)greallocn(curve, size, sizeof(GBool)); } x[n] = x1; y[n] = y1; x[n+1] = x2; y[n+1] = y2; x[n+2] = x3; y[n+2] = y3; curve[n] = curve[n+1] = gTrue; curve[n+2] = gFalse; n += 3; } void GfxSubpath::close() { if (x[n-1] != x[0] || y[n-1] != y[0]) { lineTo(x[0], y[0]); } closed = gTrue; } void GfxSubpath::offset(double dx, double dy) { int i; for (i = 0; i < n; ++i) { x[i] += dx; y[i] += dy; } } GfxPath::GfxPath() { justMoved = gFalse; size = 16; n = 0; firstX = firstY = 0; subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); } GfxPath::~GfxPath() { int i; for (i = 0; i < n; ++i) delete subpaths[i]; gfree(subpaths); } // Used for copy(). GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1, GfxSubpath **subpaths1, int n1, int size1) { int i; justMoved = justMoved1; firstX = firstX1; firstY = firstY1; size = size1; n = n1; subpaths = (GfxSubpath **)gmallocn(size, sizeof(GfxSubpath *)); for (i = 0; i < n; ++i) subpaths[i] = subpaths1[i]->copy(); } void GfxPath::moveTo(double x, double y) { justMoved = gTrue; firstX = x; firstY = y; } void GfxPath::lineTo(double x, double y) { if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) { if (n >= size) { size *= 2; subpaths = (GfxSubpath **) greallocn(subpaths, size, sizeof(GfxSubpath *)); } if (justMoved) { subpaths[n] = new GfxSubpath(firstX, firstY); } else { subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(), subpaths[n-1]->getLastY()); } ++n; justMoved = gFalse; } subpaths[n-1]->lineTo(x, y); } void GfxPath::curveTo(double x1, double y1, double x2, double y2, double x3, double y3) { if (justMoved || (n > 0 && subpaths[n-1]->isClosed())) { if (n >= size) { size *= 2; subpaths = (GfxSubpath **) greallocn(subpaths, size, sizeof(GfxSubpath *)); } if (justMoved) { subpaths[n] = new GfxSubpath(firstX, firstY); } else { subpaths[n] = new GfxSubpath(subpaths[n-1]->getLastX(), subpaths[n-1]->getLastY()); } ++n; justMoved = gFalse; } subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3); } void GfxPath::close() { // this is necessary to handle the pathological case of // moveto/closepath/clip, which defines an empty clipping region if (justMoved) { if (n >= size) { size *= 2; subpaths = (GfxSubpath **) greallocn(subpaths, size, sizeof(GfxSubpath *)); } subpaths[n] = new GfxSubpath(firstX, firstY); ++n; justMoved = gFalse; } subpaths[n-1]->close(); } void GfxPath::append(GfxPath *path) { int i; if (n + path->n > size) { size = n + path->n; subpaths = (GfxSubpath **) greallocn(subpaths, size, sizeof(GfxSubpath *)); } for (i = 0; i < path->n; ++i) { subpaths[n++] = path->subpaths[i]->copy(); } justMoved = gFalse; } void GfxPath::offset(double dx, double dy) { int i; for (i = 0; i < n; ++i) { subpaths[i]->offset(dx, dy); } } //------------------------------------------------------------------------ // GfxState //------------------------------------------------------------------------ GfxState::GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, int rotateA, GBool upsideDown) { double kx, ky; hDPI = hDPIA; vDPI = vDPIA; rotate = rotateA; px1 = pageBox->x1; py1 = pageBox->y1; px2 = pageBox->x2; py2 = pageBox->y2; kx = hDPI / 72.0; ky = vDPI / 72.0; if (rotate == 90) { ctm[0] = 0; ctm[1] = upsideDown ? ky : -ky; ctm[2] = kx; ctm[3] = 0; ctm[4] = -kx * py1; ctm[5] = ky * (upsideDown ? -px1 : px2); pageWidth = kx * (py2 - py1); pageHeight = ky * (px2 - px1); } else if (rotate == 180) { ctm[0] = -kx; ctm[1] = 0; ctm[2] = 0; ctm[3] = upsideDown ? ky : -ky; ctm[4] = kx * px2; ctm[5] = ky * (upsideDown ? -py1 : py2); pageWidth = kx * (px2 - px1); pageHeight = ky * (py2 - py1); } else if (rotate == 270) { ctm[0] = 0; ctm[1] = upsideDown ? -ky : ky; ctm[2] = -kx; ctm[3] = 0; ctm[4] = kx * py2; ctm[5] = ky * (upsideDown ? px2 : -px1); pageWidth = kx * (py2 - py1); pageHeight = ky * (px2 - px1); } else { ctm[0] = kx; ctm[1] = 0; ctm[2] = 0; ctm[3] = upsideDown ? -ky : ky; ctm[4] = -kx * px1; ctm[5] = ky * (upsideDown ? py2 : -py1); pageWidth = kx * (px2 - px1); pageHeight = ky * (py2 - py1); } fillColorSpace = new GfxDeviceGrayColorSpace(); strokeColorSpace = new GfxDeviceGrayColorSpace(); fillColor.c[0] = 0; strokeColor.c[0] = 0; fillPattern = NULL; strokePattern = NULL; blendMode = gfxBlendNormal; fillOpacity = 1; strokeOpacity = 1; fillOverprint = gFalse; strokeOverprint = gFalse; overprintMode = 0; transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL; lineWidth = 1; lineDash = NULL; lineDashLength = 0; lineDashStart = 0; flatness = 1; lineJoin = 0; lineCap = 0; miterLimit = 10; strokeAdjust = gFalse; font = NULL; fontSize = 0; textMat[0] = 1; textMat[1] = 0; textMat[2] = 0; textMat[3] = 1; textMat[4] = 0; textMat[5] = 0; charSpace = 0; wordSpace = 0; horizScaling = 1; leading = 0; rise = 0; render = 0; path = new GfxPath(); curX = curY = 0; lineX = lineY = 0; clipXMin = 0; clipYMin = 0; clipXMax = pageWidth; clipYMax = pageHeight; saved = NULL; } GfxState::~GfxState() { int i; if (fillColorSpace) { delete fillColorSpace; } if (strokeColorSpace) { delete strokeColorSpace; } if (fillPattern) { delete fillPattern; } if (strokePattern) { delete strokePattern; } for (i = 0; i < 4; ++i) { if (transfer[i]) { delete transfer[i]; } } gfree(lineDash); if (path) { // this gets set to NULL by restore() delete path; } } // Used for copy(); GfxState::GfxState(GfxState *state, GBool copyPath) { int i; memcpy(this, state, sizeof(GfxState)); if (fillColorSpace) { fillColorSpace = state->fillColorSpace->copy(); } if (strokeColorSpace) { strokeColorSpace = state->strokeColorSpace->copy(); } if (fillPattern) { fillPattern = state->fillPattern->copy(); } if (strokePattern) { strokePattern = state->strokePattern->copy(); } for (i = 0; i < 4; ++i) { if (transfer[i]) { transfer[i] = state->transfer[i]->copy(); } } if (lineDashLength > 0) { lineDash = (double *)gmallocn(lineDashLength, sizeof(double)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double)); } if (copyPath) { path = state->path->copy(); } saved = NULL; } void GfxState::setPath(GfxPath *pathA) { delete path; path = pathA; } void GfxState::getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) { double ictm[6]; double xMin1, yMin1, xMax1, yMax1, det, tx, ty; // invert the CTM det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); ictm[0] = ctm[3] * det; ictm[1] = -ctm[1] * det; ictm[2] = -ctm[2] * det; ictm[3] = ctm[0] * det; ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; // transform all four corners of the clip bbox; find the min and max // x and y values xMin1 = xMax1 = clipXMin * ictm[0] + clipYMin * ictm[2] + ictm[4]; yMin1 = yMax1 = clipXMin * ictm[1] + clipYMin * ictm[3] + ictm[5]; tx = clipXMin * ictm[0] + clipYMax * ictm[2] + ictm[4]; ty = clipXMin * ictm[1] + clipYMax * ictm[3] + ictm[5]; if (tx < xMin1) { xMin1 = tx; } else if (tx > xMax1) { xMax1 = tx; } if (ty < yMin1) { yMin1 = ty; } else if (ty > yMax1) { yMax1 = ty; } tx = clipXMax * ictm[0] + clipYMin * ictm[2] + ictm[4]; ty = clipXMax * ictm[1] + clipYMin * ictm[3] + ictm[5]; if (tx < xMin1) { xMin1 = tx; } else if (tx > xMax1) { xMax1 = tx; } if (ty < yMin1) { yMin1 = ty; } else if (ty > yMax1) { yMax1 = ty; } tx = clipXMax * ictm[0] + clipYMax * ictm[2] + ictm[4]; ty = clipXMax * ictm[1] + clipYMax * ictm[3] + ictm[5]; if (tx < xMin1) { xMin1 = tx; } else if (tx > xMax1) { xMax1 = tx; } if (ty < yMin1) { yMin1 = ty; } else if (ty > yMax1) { yMax1 = ty; } *xMin = xMin1; *yMin = yMin1; *xMax = xMax1; *yMax = yMax1; } double GfxState::transformWidth(double w) { double x, y; x = ctm[0] + ctm[2]; y = ctm[1] + ctm[3]; return w * sqrt(0.5 * (x * x + y * y)); } double GfxState::getTransformedFontSize() { double x1, y1, x2, y2; x1 = textMat[2] * fontSize; y1 = textMat[3] * fontSize; x2 = ctm[0] * x1 + ctm[2] * y1; y2 = ctm[1] * x1 + ctm[3] * y1; return sqrt(x2 * x2 + y2 * y2); } void GfxState::getFontTransMat(double *m11, double *m12, double *m21, double *m22) { *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize; *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize; *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize; *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize; } void GfxState::setCTM(double a, double b, double c, double d, double e, double f) { int i; ctm[0] = a; ctm[1] = b; ctm[2] = c; ctm[3] = d; ctm[4] = e; ctm[5] = f; // avoid FP exceptions on badly messed up PDF files for (i = 0; i < 6; ++i) { if (ctm[i] > 1e10) { ctm[i] = 1e10; } else if (ctm[i] < -1e10) { ctm[i] = -1e10; } } } void GfxState::concatCTM(double a, double b, double c, double d, double e, double f) { double a1 = ctm[0]; double b1 = ctm[1]; double c1 = ctm[2]; double d1 = ctm[3]; int i; ctm[0] = a * a1 + b * c1; ctm[1] = a * b1 + b * d1; ctm[2] = c * a1 + d * c1; ctm[3] = c * b1 + d * d1; ctm[4] = e * a1 + f * c1 + ctm[4]; ctm[5] = e * b1 + f * d1 + ctm[5]; // avoid FP exceptions on badly messed up PDF files for (i = 0; i < 6; ++i) { if (ctm[i] > 1e10) { ctm[i] = 1e10; } else if (ctm[i] < -1e10) { ctm[i] = -1e10; } } } void GfxState::shiftCTM(double tx, double ty) { ctm[4] += tx; ctm[5] += ty; clipXMin += tx; clipYMin += ty; clipXMax += tx; clipYMax += ty; } void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) { if (fillColorSpace) { delete fillColorSpace; } fillColorSpace = colorSpace; } void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) { if (strokeColorSpace) { delete strokeColorSpace; } strokeColorSpace = colorSpace; } void GfxState::setFillPattern(GfxPattern *pattern) { if (fillPattern) { delete fillPattern; } fillPattern = pattern; } void GfxState::setStrokePattern(GfxPattern *pattern) { if (strokePattern) { delete strokePattern; } strokePattern = pattern; } void GfxState::setTransfer(Function **funcs) { int i; for (i = 0; i < 4; ++i) { if (transfer[i]) { delete transfer[i]; } transfer[i] = funcs[i]; } } void GfxState::setLineDash(double *dash, int length, double start) { if (lineDash) gfree(lineDash); lineDash = dash; lineDashLength = length; lineDashStart = start; } void GfxState::clearPath() { delete path; path = new GfxPath(); } void GfxState::clip() { double xMin, yMin, xMax, yMax, x, y; GfxSubpath *subpath; int i, j; xMin = xMax = yMin = yMax = 0; // make gcc happy for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); for (j = 0; j < subpath->getNumPoints(); ++j) { transform(subpath->getX(j), subpath->getY(j), &x, &y); if (i == 0 && j == 0) { xMin = xMax = x; yMin = yMax = y; } else { if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } } } } if (xMin > clipXMin) { clipXMin = xMin; } if (yMin > clipYMin) { clipYMin = yMin; } if (xMax < clipXMax) { clipXMax = xMax; } if (yMax < clipYMax) { clipYMax = yMax; } } void GfxState::clipToStrokePath() { double xMin, yMin, xMax, yMax, x, y, t0, t1; GfxSubpath *subpath; int i, j; xMin = xMax = yMin = yMax = 0; // make gcc happy for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); for (j = 0; j < subpath->getNumPoints(); ++j) { transform(subpath->getX(j), subpath->getY(j), &x, &y); if (i == 0 && j == 0) { xMin = xMax = x; yMin = yMax = y; } else { if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } } } } // allow for the line width //~ miter joins can extend farther than this t0 = fabs(ctm[0]); t1 = fabs(ctm[2]); if (t0 > t1) { xMin -= 0.5 * lineWidth * t0; xMax += 0.5 * lineWidth * t0; } else { xMin -= 0.5 * lineWidth * t1; xMax += 0.5 * lineWidth * t1; } t0 = fabs(ctm[0]); t1 = fabs(ctm[3]); if (t0 > t1) { yMin -= 0.5 * lineWidth * t0; yMax += 0.5 * lineWidth * t0; } else { yMin -= 0.5 * lineWidth * t1; yMax += 0.5 * lineWidth * t1; } if (xMin > clipXMin) { clipXMin = xMin; } if (yMin > clipYMin) { clipYMin = yMin; } if (xMax < clipXMax) { clipXMax = xMax; } if (yMax < clipYMax) { clipYMax = yMax; } } void GfxState::clipToRect(double xMin, double yMin, double xMax, double yMax) { double x, y, xMin1, yMin1, xMax1, yMax1; transform(xMin, yMin, &x, &y); xMin1 = xMax1 = x; yMin1 = yMax1 = y; transform(xMax, yMin, &x, &y); if (x < xMin1) { xMin1 = x; } else if (x > xMax1) { xMax1 = x; } if (y < yMin1) { yMin1 = y; } else if (y > yMax1) { yMax1 = y; } transform(xMax, yMax, &x, &y); if (x < xMin1) { xMin1 = x; } else if (x > xMax1) { xMax1 = x; } if (y < yMin1) { yMin1 = y; } else if (y > yMax1) { yMax1 = y; } transform(xMin, yMax, &x, &y); if (x < xMin1) { xMin1 = x; } else if (x > xMax1) { xMax1 = x; } if (y < yMin1) { yMin1 = y; } else if (y > yMax1) { yMax1 = y; } if (xMin1 > clipXMin) { clipXMin = xMin1; } if (yMin1 > clipYMin) { clipYMin = yMin1; } if (xMax1 < clipXMax) { clipXMax = xMax1; } if (yMax1 < clipYMax) { clipYMax = yMax1; } } void GfxState::textShift(double tx, double ty) { double dx, dy; textTransformDelta(tx, ty, &dx, &dy); curX += dx; curY += dy; } void GfxState::shift(double dx, double dy) { curX += dx; curY += dy; } GfxState *GfxState::save() { GfxState *newState; newState = copy(); newState->saved = this; return newState; } GfxState *GfxState::restore() { GfxState *oldState; if (saved) { oldState = saved; // these attributes aren't saved/restored by the q/Q operators oldState->path = path; oldState->curX = curX; oldState->curY = curY; oldState->lineX = lineX; oldState->lineY = lineY; path = NULL; saved = NULL; delete this; } else { oldState = this; } return oldState; } GBool GfxState::parseBlendMode(Object *obj, GfxBlendMode *mode) { Object obj2; int i, j; if (obj->isName()) { for (i = 0; i < nGfxBlendModeNames; ++i) { if (!strcmp(obj->getName(), gfxBlendModeNames[i].name)) { *mode = gfxBlendModeNames[i].mode; return gTrue; } } return gFalse; } else if (obj->isArray()) { for (i = 0; i < obj->arrayGetLength(); ++i) { obj->arrayGet(i, &obj2); if (!obj2.isName()) { obj2.free(); return gFalse; } for (j = 0; j < nGfxBlendModeNames; ++j) { if (!strcmp(obj2.getName(), gfxBlendModeNames[j].name)) { obj2.free(); *mode = gfxBlendModeNames[j].mode; return gTrue; } } obj2.free(); } *mode = gfxBlendNormal; return gTrue; } else { return gFalse; } } xpdf-3.03/xpdf/print.xbm0000644000076400007640000000042311622305345014517 0ustar dereknderekn#define print_width 15 #define print_height 15 static unsigned char print_bits[] = { 0xf0, 0x7f, 0x10, 0x40, 0x10, 0x40, 0xc8, 0x23, 0x08, 0x20, 0x68, 0x23, 0x04, 0x10, 0x34, 0x10, 0x04, 0x10, 0xff, 0x7f, 0x55, 0x55, 0xab, 0x6a, 0x55, 0x55, 0xab, 0x6a, 0xfe, 0x3f}; xpdf-3.03/xpdf/ImageOutputDev.cc0000644000076400007640000001147711622305345016077 0ustar dereknderekn//======================================================================== // // ImageOutputDev.cc // // Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include "gmem.h" #include "config.h" #include "Error.h" #include "GfxState.h" #include "Object.h" #include "Stream.h" #include "ImageOutputDev.h" ImageOutputDev::ImageOutputDev(char *fileRootA, GBool dumpJPEGA) { fileRoot = copyString(fileRootA); fileName = (char *)gmalloc((int)strlen(fileRoot) + 20); dumpJPEG = dumpJPEGA; imgNum = 0; ok = gTrue; } ImageOutputDev::~ImageOutputDev() { gfree(fileName); gfree(fileRoot); } void ImageOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) { // do nothing -- this avoids the potentially slow loop in Gfx.cc } void ImageOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { FILE *f; int c; int size, i; // dump JPEG file if (dumpJPEG && str->getKind() == strDCT && !inlineImg) { // open the image file sprintf(fileName, "%s-%03d.jpg", fileRoot, imgNum); ++imgNum; if (!(f = fopen(fileName, "wb"))) { error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); return; } // initialize stream str = ((DCTStream *)str)->getRawStream(); str->reset(); // copy the stream while ((c = str->getChar()) != EOF) fputc(c, f); str->close(); fclose(f); // dump PBM file } else { // open the image file and write the PBM header sprintf(fileName, "%s-%03d.pbm", fileRoot, imgNum); ++imgNum; if (!(f = fopen(fileName, "wb"))) { error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); return; } fprintf(f, "P4\n"); fprintf(f, "%d %d\n", width, height); // initialize stream str->reset(); // copy the stream size = height * ((width + 7) / 8); for (i = 0; i < size; ++i) { fputc(str->getChar(), f); } str->close(); fclose(f); } } void ImageOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { FILE *f; ImageStream *imgStr; Guchar *p; GfxRGB rgb; int x, y; int c; int size, i; // dump JPEG file if (dumpJPEG && str->getKind() == strDCT && (colorMap->getNumPixelComps() == 1 || colorMap->getNumPixelComps() == 3) && !inlineImg) { // open the image file sprintf(fileName, "%s-%03d.jpg", fileRoot, imgNum); ++imgNum; if (!(f = fopen(fileName, "wb"))) { error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); return; } // initialize stream str = ((DCTStream *)str)->getRawStream(); str->reset(); // copy the stream while ((c = str->getChar()) != EOF) fputc(c, f); str->close(); fclose(f); // dump PBM file } else if (colorMap->getNumPixelComps() == 1 && colorMap->getBits() == 1) { // open the image file and write the PBM header sprintf(fileName, "%s-%03d.pbm", fileRoot, imgNum); ++imgNum; if (!(f = fopen(fileName, "wb"))) { error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); return; } fprintf(f, "P4\n"); fprintf(f, "%d %d\n", width, height); // initialize stream str->reset(); // copy the stream size = height * ((width + 7) / 8); for (i = 0; i < size; ++i) { fputc(str->getChar() ^ 0xff, f); } str->close(); fclose(f); // dump PPM file } else { // open the image file and write the PPM header sprintf(fileName, "%s-%03d.ppm", fileRoot, imgNum); ++imgNum; if (!(f = fopen(fileName, "wb"))) { error(errIO, -1, "Couldn't open image file '{0:s}'", fileName); return; } fprintf(f, "P6\n"); fprintf(f, "%d %d\n", width, height); fprintf(f, "255\n"); // initialize stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); // for each line... for (y = 0; y < height; ++y) { // write the line if ((p = imgStr->getLine())) { for (x = 0; x < width; ++x) { colorMap->getRGB(p, &rgb); fputc(colToByte(rgb.r), f); fputc(colToByte(rgb.g), f); fputc(colToByte(rgb.b), f); p += colorMap->getNumPixelComps(); } } else { for (x = 0; x < width; ++x) { fputc(0, f); fputc(0, f); fputc(0, f); } } } delete imgStr; fclose(f); } } xpdf-3.03/xpdf/CompactFontTables.h0000644000076400007640000002027311622305345016401 0ustar dereknderekn//======================================================================== // // CompactFontTables.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef COMPACTFONTINFO_H #define COMPACTFONTINFO_H static char *type1CStdStrings[391] = { ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" }; static Gushort type1CISOAdobeCharset[229] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228 }; static Gushort type1CExpertCharset[166] = { 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378 }; static Gushort type1CExpertSubsetCharset[87] = { 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346 }; #endif xpdf-3.03/xpdf/XRef.h0000644000076400007640000000742411622305345013700 0ustar dereknderekn//======================================================================== // // XRef.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XREF_H #define XREF_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" class Dict; class Stream; class Parser; class ObjectStream; //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ enum XRefEntryType { xrefEntryFree, xrefEntryUncompressed, xrefEntryCompressed }; struct XRefEntry { Guint offset; int gen; XRefEntryType type; }; class XRef { public: // Constructor. Read xref table from stream. XRef(BaseStream *strA, GBool repair); // Destructor. ~XRef(); // Is xref table valid? GBool isOk() { return ok; } // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } // Set the encryption parameters. void setEncryption(int permFlagsA, GBool ownerPasswordOkA, Guchar *fileKeyA, int keyLengthA, int encVersionA, CryptAlgorithm encAlgorithmA); // Is the file encrypted? GBool isEncrypted() { return encrypted; } // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse); GBool okToChange(GBool ignoreOwnerPW = gFalse); GBool okToCopy(GBool ignoreOwnerPW = gFalse); GBool okToAddNotes(GBool ignoreOwnerPW = gFalse); int getPermFlags() { return permFlags; } // Get catalog object. Object *getCatalog(Object *obj) { return fetch(rootNum, rootGen, obj); } // Fetch an indirect reference. Object *fetch(int num, int gen, Object *obj, int recursion = 0); // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj); Object *getDocInfoNF(Object *obj); // Return the number of objects in the xref table. int getNumObjects() { return last + 1; } // Return the offset of the last xref table. Guint getLastXRefPos() { return lastXRefPos; } // Return the catalog object reference. int getRootNum() { return rootNum; } int getRootGen() { return rootGen; } // Get end position for a stream in a damaged file. // Returns false if unknown or file is not damaged. GBool getStreamEnd(Guint streamStart, Guint *streamEnd); // Direct access. int getSize() { return size; } XRefEntry *getEntry(int i) { return &entries[i]; } Object *getTrailerDict() { return &trailerDict; } private: BaseStream *str; // input stream Guint start; // offset in file (to allow for garbage // at beginning of file) XRefEntry *entries; // xref entries int size; // size of array int last; // last used index in int rootNum, rootGen; // catalog dict GBool ok; // true if xref table is valid int errCode; // error code (if is false) Object trailerDict; // trailer dictionary Guint lastXRefPos; // offset of last xref table Guint *streamEnds; // 'endstream' positions - only used in // damaged files int streamEndsLen; // number of valid entries in streamEnds ObjectStream *objStr; // cached object stream GBool encrypted; // true if file is encrypted int permFlags; // permission bits GBool ownerPasswordOk; // true if owner password is correct Guchar fileKey[32]; // file decryption key int keyLength; // length of key, in bytes int encVersion; // encryption version CryptAlgorithm encAlgorithm; // encryption algorithm Guint getStartXref(); GBool readXRef(Guint *pos); GBool readXRefTable(Parser *parser, Guint *pos); GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); GBool readXRefStream(Stream *xrefStr, Guint *pos); GBool constructXRef(); Guint strToUnsigned(char *s); }; #endif xpdf-3.03/xpdf/FontEncodingTables.cc0000644000076400007640000005145411622305345016704 0ustar dereknderekn//======================================================================== // // FontEncodingTables.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include "FontEncodingTables.h" const char *macRomanEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL, "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Omega", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "Delta", "guillemotleft", "guillemotright", "ellipsis", "space", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "apple", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "macron", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron" }; const char *macExpertEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclamsmall", "Hungarumlautsmall", "centoldstyle", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", NULL, "threequartersemdash", NULL, "questionsmall", NULL, NULL, NULL, NULL, "Ethsmall", NULL, NULL, "onequarter", "onehalf", "threequarters", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", NULL, NULL, NULL, NULL, NULL, NULL, "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", NULL, "parenrightinferior", "Circumflexsmall", "hypheninferior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", NULL, NULL, "asuperior", "centsuperior", NULL, NULL, NULL, NULL, "Aacutesmall", "Agravesmall", "Acircumflexsmall", "Adieresissmall", "Atildesmall", "Aringsmall", "Ccedillasmall", "Eacutesmall", "Egravesmall", "Ecircumflexsmall", "Edieresissmall", "Iacutesmall", "Igravesmall", "Icircumflexsmall", "Idieresissmall", "Ntildesmall", "Oacutesmall", "Ogravesmall", "Ocircumflexsmall", "Odieresissmall", "Otildesmall", "Uacutesmall", "Ugravesmall", "Ucircumflexsmall", "Udieresissmall", NULL, "eightsuperior", "fourinferior", "threeinferior", "sixinferior", "eightinferior", "seveninferior", "Scaronsmall", NULL, "centinferior", "twoinferior", NULL, "Dieresissmall", NULL, "Caronsmall", "osuperior", "fiveinferior", NULL, "commainferior", "periodinferior", "Yacutesmall", NULL, "dollarinferior", NULL, NULL, "Thornsmall", NULL, "nineinferior", "zeroinferior", "Zcaronsmall", "AEsmall", "Oslashsmall", "questiondownsmall", "oneinferior", "Lslashsmall", NULL, NULL, NULL, NULL, NULL, NULL, "Cedillasmall", NULL, NULL, NULL, NULL, NULL, "OEsmall", "figuredash", "hyphensuperior", NULL, NULL, NULL, NULL, "exclamdownsmall", NULL, "Ydieresissmall", NULL, "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "ninesuperior", "zerosuperior", NULL, "esuperior", "rsuperior", "tsuperior", NULL, NULL, "isuperior", "ssuperior", "dsuperior", NULL, NULL, NULL, NULL, NULL, "lsuperior", "Ogoneksmall", "Brevesmall", "Macronsmall", "bsuperior", "nsuperior", "msuperior", "commasuperior", "periodsuperior", "Dotaccentsmall", "Ringsmall", NULL, NULL, NULL, NULL }; const char *winAnsiEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "bullet", "Euro", "bullet", "quotesinglbase", "florin", "quotedblbase", "ellipsis", "dagger", "daggerdbl", "circumflex", "perthousand", "Scaron", "guilsinglleft", "OE", "bullet", "Zcaron", "bullet", "bullet", "quoteleft", "quoteright", "quotedblleft", "quotedblright", "bullet", "endash", "emdash", "tilde", "trademark", "scaron", "guilsinglright", "oe", "bullet", "zcaron", "Ydieresis", "space", "exclamdown", "cent", "sterling", "currency", "yen", "brokenbar", "section", "dieresis", "copyright", "ordfeminine", "guillemotleft", "logicalnot", "hyphen", "registered", "macron", "degree", "plusminus", "twosuperior", "threesuperior", "acute", "mu", "paragraph", "periodcentered", "cedilla", "onesuperior", "ordmasculine", "guillemotright", "onequarter", "onehalf", "threequarters", "questiondown", "Agrave", "Aacute", "Acircumflex", "Atilde", "Adieresis", "Aring", "AE", "Ccedilla", "Egrave", "Eacute", "Ecircumflex", "Edieresis", "Igrave", "Iacute", "Icircumflex", "Idieresis", "Eth", "Ntilde", "Ograve", "Oacute", "Ocircumflex", "Otilde", "Odieresis", "multiply", "Oslash", "Ugrave", "Uacute", "Ucircumflex", "Udieresis", "Yacute", "Thorn", "germandbls", "agrave", "aacute", "acircumflex", "atilde", "adieresis", "aring", "ae", "ccedilla", "egrave", "eacute", "ecircumflex", "edieresis", "igrave", "iacute", "icircumflex", "idieresis", "eth", "ntilde", "ograve", "oacute", "ocircumflex", "otilde", "odieresis", "divide", "oslash", "ugrave", "uacute", "ucircumflex", "udieresis", "yacute", "thorn", "ydieresis" }; const char *standardEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", NULL, "endash", "dagger", "daggerdbl", "periodcentered", NULL, "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", NULL, "questiondown", NULL, "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", NULL, "ring", "cedilla", NULL, "hungarumlaut", "ogonek", "caron", "emdash", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "AE", NULL, "ordfeminine", NULL, NULL, NULL, NULL, "Lslash", "Oslash", "OE", "ordmasculine", NULL, NULL, NULL, NULL, NULL, "ae", NULL, NULL, NULL, "dotlessi", NULL, NULL, "lslash", "oslash", "oe", "germandbls", NULL, NULL, NULL, NULL }; const char *expertEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclamsmall", "Hungarumlautsmall", NULL, "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", NULL, "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", NULL, NULL, NULL, "isuperior", NULL, NULL, "lsuperior", "msuperior", "nsuperior", "osuperior", NULL, NULL, "rsuperior", "ssuperior", "tsuperior", NULL, "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", NULL, "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "exclamdownsmall", "centoldstyle", "Lslashsmall", NULL, NULL, "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", NULL, "Dotaccentsmall", NULL, NULL, "Macronsmall", NULL, NULL, "figuredash", "hypheninferior", NULL, NULL, "Ogoneksmall", "Ringsmall", "Cedillasmall", NULL, NULL, NULL, "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", NULL, NULL, "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall" }; const char *symbolEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "universal", "numbersign", "existential", "percent", "ampersand", "suchthat", "parenleft", "parenright", "asteriskmath", "plus", "comma", "minus", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "congruent", "Alpha", "Beta", "Chi", "Delta", "Epsilon", "Phi", "Gamma", "Eta", "Iota", "theta1", "Kappa", "Lambda", "Mu", "Nu", "Omicron", "Pi", "Theta", "Rho", "Sigma", "Tau", "Upsilon", "sigma1", "Omega", "Xi", "Psi", "Zeta", "bracketleft", "therefore", "bracketright", "perpendicular", "underscore", "radicalex", "alpha", "beta", "chi", "delta", "epsilon", "phi", "gamma", "eta", "iota", "phi1", "kappa", "lambda", "mu", "nu", "omicron", "pi", "theta", "rho", "sigma", "tau", "upsilon", "omega1", "omega", "xi", "psi", "zeta", "braceleft", "bar", "braceright", "similar", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Upsilon1", "minute", "lessequal", "fraction", "infinity", "florin", "club", "diamond", "heart", "spade", "arrowboth", "arrowleft", "arrowup", "arrowright", "arrowdown", "degree", "plusminus", "second", "greaterequal", "multiply", "proportional", "partialdiff", "bullet", "divide", "notequal", "equivalence", "approxequal", "ellipsis", "arrowvertex", "arrowhorizex", "carriagereturn", "aleph", "Ifraktur", "Rfraktur", "weierstrass", "circlemultiply", "circleplus", "emptyset", "intersection", "union", "propersuperset", "reflexsuperset", "notsubset", "propersubset", "reflexsubset", "element", "notelement", "angle", "gradient", "registerserif", "copyrightserif", "trademarkserif", "product", "radical", "dotmath", "logicalnot", "logicaland", "logicalor", "arrowdblboth", "arrowdblleft", "arrowdblup", "arrowdblright", "arrowdbldown", "lozenge", "angleleft", "registersans", "copyrightsans", "trademarksans", "summation", "parenlefttp", "parenleftex", "parenleftbt", "bracketlefttp", "bracketleftex", "bracketleftbt", "bracelefttp", "braceleftmid", "braceleftbt", "braceex", NULL, "angleright", "integral", "integraltp", "integralex", "integralbt", "parenrighttp", "parenrightex", "parenrightbt", "bracketrighttp", "bracketrightex", "bracketrightbt", "bracerighttp", "bracerightmid", "bracerightbt", NULL }; const char *zapfDingbatsEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "a1", "a2", "a202", "a3", "a4", "a5", "a119", "a118", "a117", "a11", "a12", "a13", "a14", "a15", "a16", "a105", "a17", "a18", "a19", "a20", "a21", "a22", "a23", "a24", "a25", "a26", "a27", "a28", "a6", "a7", "a8", "a9", "a10", "a29", "a30", "a31", "a32", "a33", "a34", "a35", "a36", "a37", "a38", "a39", "a40", "a41", "a42", "a43", "a44", "a45", "a46", "a47", "a48", "a49", "a50", "a51", "a52", "a53", "a54", "a55", "a56", "a57", "a58", "a59", "a60", "a61", "a62", "a63", "a64", "a65", "a66", "a67", "a68", "a69", "a70", "a71", "a72", "a73", "a74", "a203", "a75", "a204", "a76", "a77", "a78", "a79", "a81", "a82", "a83", "a84", "a97", "a98", "a99", "a100", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "a101", "a102", "a103", "a104", "a106", "a107", "a108", "a112", "a111", "a110", "a109", "a120", "a121", "a122", "a123", "a124", "a125", "a126", "a127", "a128", "a129", "a130", "a131", "a132", "a133", "a134", "a135", "a136", "a137", "a138", "a139", "a140", "a141", "a142", "a143", "a144", "a145", "a146", "a147", "a148", "a149", "a150", "a151", "a152", "a153", "a154", "a155", "a156", "a157", "a158", "a159", "a160", "a161", "a163", "a164", "a196", "a165", "a192", "a166", "a167", "a168", "a169", "a170", "a171", "a172", "a173", "a162", "a174", "a175", "a176", "a177", "a178", "a179", "a193", "a180", "a199", "a181", "a200", "a182", NULL, "a201", "a183", "a184", "a197", "a185", "a194", "a198", "a186", "a195", "a187", "a188", "a189", "a190", "a191", NULL }; xpdf-3.03/xpdf/rightArrowDis.xbm0000644000076400007640000000031511622305345016153 0ustar dereknderekn#define rightArrowDis_width 8 #define rightArrowDis_height 15 static unsigned char rightArrowDis_bits[] = { 0x01, 0x02, 0x05, 0x0a, 0x15, 0x2a, 0x55, 0xaa, 0x55, 0x2a, 0x15, 0x0a, 0x05, 0x02, 0x01}; xpdf-3.03/xpdf/pdftotext.cc0000644000076400007640000002164511622305345015214 0ustar dereknderekn//======================================================================== // // pdftotext.cc // // Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include #include #include #include "parseargs.h" #include "GString.h" #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "Stream.h" #include "Array.h" #include "Dict.h" #include "XRef.h" #include "Catalog.h" #include "Page.h" #include "PDFDoc.h" #include "TextOutputDev.h" #include "CharTypes.h" #include "UnicodeMap.h" #include "Error.h" #include "config.h" static void printInfoString(FILE *f, Dict *infoDict, const char *key, const char *text1, const char *text2, UnicodeMap *uMap); static void printInfoDate(FILE *f, Dict *infoDict, const char *key, const char *fmt); static int firstPage = 1; static int lastPage = 0; static GBool physLayout = gFalse; static double fixedPitch = 0; static GBool rawOrder = gFalse; static GBool htmlMeta = gFalse; static char textEncName[128] = ""; static char textEOL[16] = ""; static GBool noPageBreaks = gFalse; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to convert"}, {"-l", argInt, &lastPage, 0, "last page to convert"}, {"-layout", argFlag, &physLayout, 0, "maintain original physical layout"}, {"-fixed", argFP, &fixedPitch, 0, "assume fixed-pitch (or tabular) text"}, {"-raw", argFlag, &rawOrder, 0, "keep strings in content stream order"}, {"-htmlmeta", argFlag, &htmlMeta, 0, "generate a simple HTML file, including the meta information"}, {"-enc", argString, textEncName, sizeof(textEncName), "output text encoding name"}, {"-eol", argString, textEOL, sizeof(textEOL), "output end-of-line convention (unix, dos, or mac)"}, {"-nopgbrk", argFlag, &noPageBreaks, 0, "don't insert page breaks between pages"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; GString *textFileName; GString *ownerPW, *userPW; TextOutputDev *textOut; FILE *f; UnicodeMap *uMap; Object info; GBool ok; char *p; int exitCode; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) { fprintf(stderr, "pdftotext version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdftotext", " []", argDesc); } goto err0; } fileName = new GString(argv[1]); if (fixedPitch) { physLayout = gTrue; } // read config file globalParams = new GlobalParams(cfgFileName); if (textEncName[0]) { globalParams->setTextEncoding(textEncName); } if (textEOL[0]) { if (!globalParams->setTextEOL(textEOL)) { fprintf(stderr, "Bad '-eol' value on command line\n"); } } if (noPageBreaks) { globalParams->setTextPageBreaks(gFalse); } if (quiet) { globalParams->setErrQuiet(quiet); } // get mapping to output encoding if (!(uMap = globalParams->getTextEncoding())) { error(errConfig, -1, "Couldn't get text encoding"); delete fileName; goto err1; } // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err2; } // check for copy permission if (!doc->okToCopy()) { error(errNotAllowed, -1, "Copying of text from this document is not allowed."); exitCode = 3; goto err2; } // construct text file name if (argc == 3) { textFileName = new GString(argv[2]); } else { p = fileName->getCString() + fileName->getLength() - 4; if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) { textFileName = new GString(fileName->getCString(), fileName->getLength() - 4); } else { textFileName = fileName->copy(); } textFileName->append(htmlMeta ? ".html" : ".txt"); } // get page range if (firstPage < 1) { firstPage = 1; } if (lastPage < 1 || lastPage > doc->getNumPages()) { lastPage = doc->getNumPages(); } // write HTML header if (htmlMeta) { if (!textFileName->cmp("-")) { f = stdout; } else { if (!(f = fopen(textFileName->getCString(), "wb"))) { error(errIO, -1, "Couldn't open text file '{0:t}'", textFileName); exitCode = 2; goto err3; } } fputs("\n", f); fputs("\n", f); doc->getDocInfo(&info); if (info.isDict()) { printInfoString(f, info.getDict(), "Title", "", "\n", uMap); printInfoString(f, info.getDict(), "Subject", "\n", uMap); printInfoString(f, info.getDict(), "Keywords", "\n", uMap); printInfoString(f, info.getDict(), "Author", "\n", uMap); printInfoString(f, info.getDict(), "Creator", "\n", uMap); printInfoString(f, info.getDict(), "Producer", "\n", uMap); printInfoDate(f, info.getDict(), "CreationDate", "\n"); printInfoDate(f, info.getDict(), "LastModifiedDate", "\n"); } info.free(); fputs("\n", f); fputs("\n", f); fputs("
\n", f);
    if (f != stdout) {
      fclose(f);
    }
  }

  // write text file
  textOut = new TextOutputDev(textFileName->getCString(),
			      physLayout, fixedPitch, rawOrder, htmlMeta);
  if (textOut->isOk()) {
    doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0,
		      gFalse, gTrue, gFalse);
  } else {
    delete textOut;
    exitCode = 2;
    goto err3;
  }
  delete textOut;

  // write end of HTML file
  if (htmlMeta) {
    if (!textFileName->cmp("-")) {
      f = stdout;
    } else {
      if (!(f = fopen(textFileName->getCString(), "ab"))) {
	error(errIO, -1, "Couldn't open text file '{0:t}'", textFileName);
	exitCode = 2;
	goto err3;
      }
    }
    fputs("
\n", f); fputs("\n", f); fputs("\n", f); if (f != stdout) { fclose(f); } } exitCode = 0; // clean up err3: delete textFileName; err2: delete doc; uMap->decRefCnt(); err1: delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } static void printInfoString(FILE *f, Dict *infoDict, const char *key, const char *text1, const char *text2, UnicodeMap *uMap) { Object obj; GString *s1; GBool isUnicode; Unicode u; char buf[8]; int i, n; if (infoDict->lookup(key, &obj)->isString()) { fputs(text1, f); s1 = obj.getString(); if ((s1->getChar(0) & 0xff) == 0xfe && (s1->getChar(1) & 0xff) == 0xff) { isUnicode = gTrue; i = 2; } else { isUnicode = gFalse; i = 0; } while (i < obj.getString()->getLength()) { if (isUnicode) { u = ((s1->getChar(i) & 0xff) << 8) | (s1->getChar(i+1) & 0xff); i += 2; } else { u = s1->getChar(i) & 0xff; ++i; } n = uMap->mapUnicode(u, buf, sizeof(buf)); fwrite(buf, 1, n, f); } fputs(text2, f); } obj.free(); } static void printInfoDate(FILE *f, Dict *infoDict, const char *key, const char *fmt) { Object obj; char *s; if (infoDict->lookup(key, &obj)->isString()) { s = obj.getString()->getCString(); if (s[0] == 'D' && s[1] == ':') { s += 2; } fprintf(f, fmt, s); } obj.free(); } xpdf-3.03/xpdf/SplashOutputDev.h0000644000076400007640000002223511622305345016143 0ustar dereknderekn//======================================================================== // // SplashOutputDev.h // // Copyright 2003 Glyph & Cog, LLC // //======================================================================== #ifndef SPLASHOUTPUTDEV_H #define SPLASHOUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "SplashTypes.h" #include "config.h" #include "OutputDev.h" #include "GfxState.h" class Gfx8BitFont; class SplashBitmap; class Splash; class SplashPath; class SplashPattern; class SplashFontEngine; class SplashFont; class T3FontCache; struct T3FontCacheTag; struct T3GlyphStack; struct SplashTransparencyGroup; //------------------------------------------------------------------------ // number of Type 3 fonts to cache #define splashOutT3FontCacheSize 8 //------------------------------------------------------------------------ // SplashOutputDev //------------------------------------------------------------------------ class SplashOutputDev: public OutputDev { public: // Constructor. SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool bitmapTopDownA = gTrue, GBool allowAntialiasA = gTrue); // Destructor. virtual ~SplashOutputDev(); //----- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return bitmapTopDown ^ bitmapUpsideDown; } // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } // Does this device use tilingPatternFill()? If this returns false, // tiling pattern fills will be reduced to a series of other drawing // operations. virtual GBool useTilingPatternFill() { return gTrue; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gTrue; } //----- initialization and control // Start a page. virtual void startPage(int pageNum, GfxState *state); // End a page. virtual void endPage(); //----- save/restore graphics state virtual void saveState(GfxState *state); virtual void restoreState(GfxState *state); //----- update graphics state virtual void updateAll(GfxState *state); virtual void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32); virtual void updateLineDash(GfxState *state); virtual void updateFlatness(GfxState *state); virtual void updateLineJoin(GfxState *state); virtual void updateLineCap(GfxState *state); virtual void updateMiterLimit(GfxState *state); virtual void updateLineWidth(GfxState *state); virtual void updateStrokeAdjust(GfxState *state); virtual void updateFillColor(GfxState *state); virtual void updateStrokeColor(GfxState *state); virtual void updateBlendMode(GfxState *state); virtual void updateFillOpacity(GfxState *state); virtual void updateStrokeOpacity(GfxState *state); virtual void updateTransfer(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); //----- path painting virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep); //----- path clipping virtual void clip(GfxState *state); virtual void eoClip(GfxState *state); virtual void clipToStrokePath(GfxState *state); //----- text drawing virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen); virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); virtual void endTextObject(GfxState *state); //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap); //----- Type 3 font operators virtual void type3D0(GfxState *state, double wx, double wy); virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury); //----- transparency groups and soft masks virtual void beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask); virtual void endTransparencyGroup(GfxState *state); virtual void paintTransparencyGroup(GfxState *state, double *bbox); virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor); virtual void clearSoftMask(GfxState *state); //----- special access // Called to indicate that a new PDF document has been loaded. void startDoc(XRef *xrefA); void setPaperColor(SplashColorPtr paperColorA); GBool isReverseVideo() { return reverseVideo; } void setReverseVideo(GBool reverseVideoA) { reverseVideo = reverseVideoA; } // Get the bitmap and its size. SplashBitmap *getBitmap() { return bitmap; } int getBitmapWidth(); int getBitmapHeight(); // Returns the last rasterized bitmap, transferring ownership to the // caller. SplashBitmap *takeBitmap(); // Set this flag to true to generate an upside-down bitmap (useful // for Windows BMP files). void setBitmapUpsideDown(GBool f) { bitmapUpsideDown = f; } // Get the Splash object. Splash *getSplash() { return splash; } // Get the modified region. void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax); // Clear the modified region. void clearModRegion(); // Set the Splash fill color. void setFillColor(int r, int g, int b); // Get a font object for a Base-14 font, using the Latin-1 encoding. SplashFont *getFont(GString *name, SplashCoord *textMatA); SplashFont *getCurrentFont() { return font; } // If is true, don't draw horizontal text. // If is true, don't draw rotated (non-horizontal) text. void setSkipText(GBool skipHorizTextA, GBool skipRotatedTextA) { skipHorizText = skipHorizTextA; skipRotatedText = skipRotatedTextA; } int getNestCount() { return nestCount; } #if 1 //~tmp: turn off anti-aliasing temporarily virtual void setInShading(GBool sh); #endif private: void setupScreenParams(double hDPI, double vDPI); SplashPattern *getColor(GfxGray gray); SplashPattern *getColor(GfxRGB *rgb); #if SPLASH_CMYK SplashPattern *getColor(GfxCMYK *cmyk); #endif void setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag, int overprintMode, GfxColor *singleColor); SplashPath *convertPath(GfxState *state, GfxPath *path, GBool dropEmptySubpaths); void doUpdateFont(GfxState *state); void drawType3Glyph(GfxState *state, T3FontCache *t3Font, T3FontCacheTag *tag, Guchar *data); static GBool imageMaskSrc(void *data, SplashColorPtr line); static GBool imageSrc(void *data, SplashColorPtr colorLine, Guchar *alphaLine); static GBool alphaImageSrc(void *data, SplashColorPtr line, Guchar *alphaLine); static GBool maskedImageSrc(void *data, SplashColorPtr line, Guchar *alphaLine); SplashColorMode colorMode; int bitmapRowPad; GBool bitmapTopDown; GBool bitmapUpsideDown; GBool allowAntialias; GBool vectorAntialias; GBool reverseVideo; // reverse video mode SplashColor paperColor; // paper color SplashScreenParams screenParams; GBool skipHorizText; GBool skipRotatedText; XRef *xref; // xref table for current document SplashBitmap *bitmap; Splash *splash; SplashFontEngine *fontEngine; T3FontCache * // Type 3 font cache t3FontCache[splashOutT3FontCacheSize]; int nT3Fonts; // number of valid entries in t3FontCache T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack GBool haveT3Dx; // set after seeing a d0/d1 operator SplashFont *font; // current font GBool needFontUpdate; // set when the font needs to be updated SplashPath *textClipPath; // clipping path built with text object SplashTransparencyGroup * // transparency group stack transpGroupStack; int nestCount; }; #endif xpdf-3.03/xpdf/XRef.cc0000644000076400007640000005076411622305345014043 0ustar dereknderekn//======================================================================== // // XRef.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "gmem.h" #include "Object.h" #include "Stream.h" #include "Lexer.h" #include "Parser.h" #include "Dict.h" #include "Error.h" #include "ErrorCodes.h" #include "XRef.h" //------------------------------------------------------------------------ #define xrefSearchSize 1024 // read this many bytes at end of file // to look for 'startxref' //------------------------------------------------------------------------ // Permission bits //------------------------------------------------------------------------ #define permPrint (1<<2) #define permChange (1<<3) #define permCopy (1<<4) #define permNotes (1<<5) #define defPermFlags 0xfffc //------------------------------------------------------------------------ // ObjectStream //------------------------------------------------------------------------ class ObjectStream { public: // Create an object stream, using object number , // generation 0. ObjectStream(XRef *xref, int objStrNumA); GBool isOk() { return ok; } ~ObjectStream(); // Return the object number of this object stream. int getObjStrNum() { return objStrNum; } // Get the th object from this stream, which should be // object number , generation 0. Object *getObject(int objIdx, int objNum, Object *obj); private: int objStrNum; // object number of the object stream int nObjects; // number of objects in the stream Object *objs; // the objects (length = nObjects) int *objNums; // the object numbers (length = nObjects) GBool ok; }; ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { Stream *str; Parser *parser; int *offsets; Object objStr, obj1, obj2; int first, i; objStrNum = objStrNumA; nObjects = 0; objs = NULL; objNums = NULL; ok = gFalse; if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { goto err1; } if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { obj1.free(); goto err1; } nObjects = obj1.getInt(); obj1.free(); if (nObjects <= 0) { goto err1; } if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { obj1.free(); goto err1; } first = obj1.getInt(); obj1.free(); if (first < 0) { goto err1; } // this is an arbitrary limit to avoid integer overflow problems // in the 'new Object[nObjects]' call (Acrobat apparently limits // object streams to 100-200 objects) if (nObjects > 1000000) { error(errSyntaxError, -1, "Too many objects in an object stream"); goto err1; } objs = new Object[nObjects]; objNums = (int *)gmallocn(nObjects, sizeof(int)); offsets = (int *)gmallocn(nObjects, sizeof(int)); // parse the header: object numbers and offsets objStr.streamReset(); obj1.initNull(); str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); parser = new Parser(xref, new Lexer(xref, str), gFalse); for (i = 0; i < nObjects; ++i) { parser->getObj(&obj1, gTrue); parser->getObj(&obj2, gTrue); if (!obj1.isInt() || !obj2.isInt()) { obj1.free(); obj2.free(); delete parser; gfree(offsets); goto err1; } objNums[i] = obj1.getInt(); offsets[i] = obj2.getInt(); obj1.free(); obj2.free(); if (objNums[i] < 0 || offsets[i] < 0 || (i > 0 && offsets[i] < offsets[i-1])) { delete parser; gfree(offsets); goto err1; } } while (str->getChar() != EOF) ; delete parser; // skip to the first object - this shouldn't be necessary because // the First key is supposed to be equal to offsets[0], but just in // case... for (i = first; i < offsets[0]; ++i) { objStr.getStream()->getChar(); } // parse the objects for (i = 0; i < nObjects; ++i) { obj1.initNull(); if (i == nObjects - 1) { str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); } else { str = new EmbedStream(objStr.getStream(), &obj1, gTrue, offsets[i+1] - offsets[i]); } parser = new Parser(xref, new Lexer(xref, str), gFalse); parser->getObj(&objs[i]); while (str->getChar() != EOF) ; delete parser; } gfree(offsets); ok = gTrue; err1: objStr.free(); } ObjectStream::~ObjectStream() { int i; if (objs) { for (i = 0; i < nObjects; ++i) { objs[i].free(); } delete[] objs; } gfree(objNums); } Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { return obj->initNull(); } return objs[objIdx].copy(obj); } //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ XRef::XRef(BaseStream *strA, GBool repair) { Guint pos; Object obj; ok = gTrue; errCode = errNone; size = 0; last = -1; entries = NULL; streamEnds = NULL; streamEndsLen = 0; objStr = NULL; encrypted = gFalse; permFlags = defPermFlags; ownerPasswordOk = gFalse; str = strA; start = str->getStart(); // if the 'repair' flag is set, try to reconstruct the xref table if (repair) { if (!(ok = constructXRef())) { errCode = errDamaged; return; } // if the 'repair' flag is not set, read the xref table } else { // read the trailer pos = getStartXref(); if (pos == 0) { errCode = errDamaged; ok = gFalse; return; } // read the xref table while (readXRef(&pos)) ; if (!ok) { errCode = errDamaged; return; } } // get the root dictionary (catalog) object trailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); obj.free(); } else { obj.free(); if (!(ok = constructXRef())) { errCode = errDamaged; return; } } // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); } XRef::~XRef() { gfree(entries); trailerDict.free(); if (streamEnds) { gfree(streamEnds); } if (objStr) { delete objStr; } } // Read the 'startxref' position. Guint XRef::getStartXref() { char buf[xrefSearchSize+1]; char *p; int c, n, i; // read last xrefSearchSize bytes str->setPos(xrefSearchSize, -1); for (n = 0; n < xrefSearchSize; ++n) { if ((c = str->getChar()) == EOF) { break; } buf[n] = c; } buf[n] = '\0'; // find startxref for (i = n - 9; i >= 0; --i) { if (!strncmp(&buf[i], "startxref", 9)) { break; } } if (i < 0) { return 0; } for (p = &buf[i+9]; isspace(*p & 0xff); ++p) ; lastXRefPos = strToUnsigned(p); return lastXRefPos; } // Read one xref table section. Also reads the associated trailer // dictionary, and returns the prev pointer (if any). GBool XRef::readXRef(Guint *pos) { Parser *parser; Object obj; GBool more; // start up a parser, parse one token obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + *pos, gFalse, 0, &obj)), gTrue); parser->getObj(&obj, gTrue); // parse an old-style xref table if (obj.isCmd("xref")) { obj.free(); more = readXRefTable(parser, pos); // parse an xref stream } else if (obj.isInt()) { obj.free(); if (!parser->getObj(&obj, gTrue)->isInt()) { goto err1; } obj.free(); if (!parser->getObj(&obj, gTrue)->isCmd("obj")) { goto err1; } obj.free(); if (!parser->getObj(&obj)->isStream()) { goto err1; } more = readXRefStream(obj.getStream(), pos); obj.free(); } else { goto err1; } delete parser; return more; err1: obj.free(); delete parser; ok = gFalse; return gFalse; } GBool XRef::readXRefTable(Parser *parser, Guint *pos) { XRefEntry entry; GBool more; Object obj, obj2; Guint pos2; int first, n, newSize, i; while (1) { parser->getObj(&obj, gTrue); if (obj.isCmd("trailer")) { obj.free(); break; } if (!obj.isInt()) { goto err1; } first = obj.getInt(); obj.free(); if (!parser->getObj(&obj, gTrue)->isInt()) { goto err1; } n = obj.getInt(); obj.free(); if (first < 0 || n < 0 || first + n < 0) { goto err1; } if (first + n > size) { for (newSize = size ? 2 * size : 1024; first + n > newSize && newSize > 0; newSize <<= 1) ; if (newSize < 0) { goto err1; } entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; } size = newSize; } for (i = first; i < first + n; ++i) { if (!parser->getObj(&obj, gTrue)->isInt()) { goto err1; } entry.offset = (Guint)obj.getInt(); obj.free(); if (!parser->getObj(&obj, gTrue)->isInt()) { goto err1; } entry.gen = obj.getInt(); obj.free(); parser->getObj(&obj, gTrue); if (obj.isCmd("n")) { entry.type = xrefEntryUncompressed; } else if (obj.isCmd("f")) { entry.type = xrefEntryFree; } else { goto err1; } obj.free(); if (entries[i].offset == 0xffffffff) { entries[i] = entry; // PDF files of patents from the IBM Intellectual Property // Network have a bug: the xref table claims to start at 1 // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && entries[1].type == xrefEntryFree) { i = first = 0; entries[0] = entries[1]; entries[1].offset = 0xffffffff; } if (i > last) { last = i; } } } } // read the trailer dictionary if (!parser->getObj(&obj)->isDict()) { goto err1; } // get the 'Prev' pointer obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { pos2 = (Guint)obj2.getInt(); if (pos2 != *pos) { *pos = pos2; more = gTrue; } else { error(errSyntaxWarning, -1, "Infinite loop in xref table"); more = gFalse; } } else if (obj2.isRef()) { // certain buggy PDF generators generate "/Prev NNN 0 R" instead // of "/Prev NNN" pos2 = (Guint)obj2.getRefNum(); if (pos2 != *pos) { *pos = pos2; more = gTrue; } else { error(errSyntaxWarning, -1, "Infinite loop in xref table"); more = gFalse; } } else { more = gFalse; } obj2.free(); // save the first trailer dictionary if (trailerDict.isNone()) { obj.copy(&trailerDict); } // check for an 'XRefStm' key if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { pos2 = (Guint)obj2.getInt(); readXRef(&pos2); if (!ok) { obj2.free(); goto err1; } } obj2.free(); obj.free(); return more; err1: obj.free(); ok = gFalse; return gFalse; } GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { Dict *dict; int w[3]; GBool more; Object obj, obj2, idx; int newSize, first, n, i; dict = xrefStr->getDict(); if (!dict->lookupNF("Size", &obj)->isInt()) { goto err1; } newSize = obj.getInt(); obj.free(); if (newSize < 0) { goto err1; } if (newSize > size) { entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; } size = newSize; } if (!dict->lookupNF("W", &obj)->isArray() || obj.arrayGetLength() < 3) { goto err1; } for (i = 0; i < 3; ++i) { if (!obj.arrayGet(i, &obj2)->isInt()) { obj2.free(); goto err1; } w[i] = obj2.getInt(); obj2.free(); if (w[i] < 0 || w[i] > 4) { goto err1; } } obj.free(); xrefStr->reset(); dict->lookupNF("Index", &idx); if (idx.isArray()) { for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { if (!idx.arrayGet(i, &obj)->isInt()) { idx.free(); goto err1; } first = obj.getInt(); obj.free(); if (!idx.arrayGet(i+1, &obj)->isInt()) { idx.free(); goto err1; } n = obj.getInt(); obj.free(); if (first < 0 || n < 0 || !readXRefStreamSection(xrefStr, w, first, n)) { idx.free(); goto err0; } } } else { if (!readXRefStreamSection(xrefStr, w, 0, newSize)) { idx.free(); goto err0; } } idx.free(); dict->lookupNF("Prev", &obj); if (obj.isInt()) { *pos = (Guint)obj.getInt(); more = gTrue; } else { more = gFalse; } obj.free(); if (trailerDict.isNone()) { trailerDict.initDict(dict); } return more; err1: obj.free(); err0: ok = gFalse; return gFalse; } GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { Guint offset; int type, gen, c, newSize, i, j; if (first + n < 0) { return gFalse; } if (first + n > size) { for (newSize = size ? 2 * size : 1024; first + n > newSize && newSize > 0; newSize <<= 1) ; if (newSize < 0) { return gFalse; } entries = (XRefEntry *)greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; } size = newSize; } for (i = first; i < first + n; ++i) { if (w[0] == 0) { type = 1; } else { for (type = 0, j = 0; j < w[0]; ++j) { if ((c = xrefStr->getChar()) == EOF) { return gFalse; } type = (type << 8) + c; } } for (offset = 0, j = 0; j < w[1]; ++j) { if ((c = xrefStr->getChar()) == EOF) { return gFalse; } offset = (offset << 8) + c; } for (gen = 0, j = 0; j < w[2]; ++j) { if ((c = xrefStr->getChar()) == EOF) { return gFalse; } gen = (gen << 8) + c; } if (entries[i].offset == 0xffffffff) { switch (type) { case 0: entries[i].offset = offset; entries[i].gen = gen; entries[i].type = xrefEntryFree; break; case 1: entries[i].offset = offset; entries[i].gen = gen; entries[i].type = xrefEntryUncompressed; break; case 2: entries[i].offset = offset; entries[i].gen = gen; entries[i].type = xrefEntryCompressed; break; default: return gFalse; } if (i > last) { last = i; } } } return gTrue; } // Attempt to construct an xref table for a damaged file. GBool XRef::constructXRef() { Parser *parser; Object newTrailerDict, obj; char buf[256]; Guint pos; int num, gen; int newSize; int streamEndsSize; char *p; int i; GBool gotRoot; gfree(entries); size = 0; entries = NULL; gotRoot = gFalse; streamEndsLen = streamEndsSize = 0; str->reset(); while (1) { pos = str->getPos(); if (!str->getLine(buf, 256)) { break; } p = buf; // skip whitespace while (*p && Lexer::isSpace(*p & 0xff)) ++p; // got trailer dictionary if (!strncmp(p, "trailer", 7)) { obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(pos + 7, gFalse, 0, &obj)), gFalse); parser->getObj(&newTrailerDict); if (newTrailerDict.isDict()) { newTrailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); if (!trailerDict.isNone()) { trailerDict.free(); } newTrailerDict.copy(&trailerDict); gotRoot = gTrue; } obj.free(); } newTrailerDict.free(); delete parser; // look for object } else if (isdigit(*p & 0xff)) { num = atoi(p); if (num > 0) { do { ++p; } while (*p && isdigit(*p & 0xff)); if (isspace(*p & 0xff)) { do { ++p; } while (*p && isspace(*p & 0xff)); if (isdigit(*p & 0xff)) { gen = atoi(p); do { ++p; } while (*p && isdigit(*p & 0xff)); if (isspace(*p & 0xff)) { do { ++p; } while (*p && isspace(*p & 0xff)); if (!strncmp(p, "obj", 3)) { if (num >= size) { newSize = (num + 1 + 255) & ~255; if (newSize < 0) { error(errSyntaxError, -1, "Bad object number"); return gFalse; } entries = (XRefEntry *) greallocn(entries, newSize, sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; entries[i].type = xrefEntryFree; } size = newSize; } if (entries[num].type == xrefEntryFree || gen >= entries[num].gen) { entries[num].offset = pos - start; entries[num].gen = gen; entries[num].type = xrefEntryUncompressed; if (num > last) { last = num; } } } } } } } } else if (!strncmp(p, "endstream", 9)) { if (streamEndsLen == streamEndsSize) { streamEndsSize += 64; streamEnds = (Guint *)greallocn(streamEnds, streamEndsSize, sizeof(Guint)); } streamEnds[streamEndsLen++] = pos; } } if (gotRoot) return gTrue; error(errSyntaxError, -1, "Couldn't find trailer dictionary"); return gFalse; } void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, Guchar *fileKeyA, int keyLengthA, int encVersionA, CryptAlgorithm encAlgorithmA) { int i; encrypted = gTrue; permFlags = permFlagsA; ownerPasswordOk = ownerPasswordOkA; if (keyLengthA <= 32) { keyLength = keyLengthA; } else { keyLength = 32; } for (i = 0; i < keyLength; ++i) { fileKey[i] = fileKeyA[i]; } encVersion = encVersionA; encAlgorithm = encAlgorithmA; } GBool XRef::okToPrint(GBool ignoreOwnerPW) { return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint); } GBool XRef::okToChange(GBool ignoreOwnerPW) { return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange); } GBool XRef::okToCopy(GBool ignoreOwnerPW) { return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy); } GBool XRef::okToAddNotes(GBool ignoreOwnerPW) { return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes); } Object *XRef::fetch(int num, int gen, Object *obj, int recursion) { XRefEntry *e; Parser *parser; Object obj1, obj2, obj3; // check for bogus ref - this can happen in corrupted PDF files if (num < 0 || num >= size) { goto err; } e = &entries[num]; switch (e->type) { case xrefEntryUncompressed: if (e->gen != gen) { goto err; } obj1.initNull(); parser = new Parser(this, new Lexer(this, str->makeSubStream(start + e->offset, gFalse, 0, &obj1)), gTrue); parser->getObj(&obj1, gTrue); parser->getObj(&obj2, gTrue); parser->getObj(&obj3, gTrue); if (!obj1.isInt() || obj1.getInt() != num || !obj2.isInt() || obj2.getInt() != gen || !obj3.isCmd("obj")) { obj1.free(); obj2.free(); obj3.free(); delete parser; goto err; } parser->getObj(obj, gFalse, encrypted ? fileKey : (Guchar *)NULL, encAlgorithm, keyLength, num, gen, recursion); obj1.free(); obj2.free(); obj3.free(); delete parser; break; case xrefEntryCompressed: #if 0 // Adobe apparently ignores the generation number on compressed objects if (gen != 0) { goto err; } #endif if (e->offset >= (Guint)size || entries[e->offset].type != xrefEntryUncompressed) { error(errSyntaxError, -1, "Invalid object stream"); goto err; } if (!objStr || objStr->getObjStrNum() != (int)e->offset) { if (objStr) { delete objStr; } objStr = new ObjectStream(this, e->offset); if (!objStr->isOk()) { delete objStr; objStr = NULL; goto err; } } objStr->getObject(e->gen, num, obj); break; default: goto err; } return obj; err: return obj->initNull(); } Object *XRef::getDocInfo(Object *obj) { return trailerDict.dictLookup("Info", obj); } // Added for the pdftex project. Object *XRef::getDocInfoNF(Object *obj) { return trailerDict.dictLookupNF("Info", obj); } GBool XRef::getStreamEnd(Guint streamStart, Guint *streamEnd) { int a, b, m; if (streamEndsLen == 0 || streamStart > streamEnds[streamEndsLen - 1]) { return gFalse; } a = -1; b = streamEndsLen - 1; // invariant: streamEnds[a] < streamStart <= streamEnds[b] while (b - a > 1) { m = (a + b) / 2; if (streamStart <= streamEnds[m]) { b = m; } else { a = m; } } *streamEnd = streamEnds[b]; return gTrue; } Guint XRef::strToUnsigned(char *s) { Guint x, d; char *p; x = 0; for (p = s; *p && isdigit(*p & 0xff); ++p) { d = *p - '0'; if (x > (UINT_MAX - d) / 10) { break; } x = 10 * x + d; } return x; } xpdf-3.03/xpdf/PreScanOutputDev.cc0000644000076400007640000002063011622305345016377 0ustar dereknderekn//======================================================================== // // PreScanOutputDev.cc // // Copyright 2005 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "GlobalParams.h" #include "Page.h" #include "Gfx.h" #include "GfxFont.h" #include "Link.h" #include "PreScanOutputDev.h" //------------------------------------------------------------------------ // PreScanOutputDev //------------------------------------------------------------------------ PreScanOutputDev::PreScanOutputDev() { clearStats(); } PreScanOutputDev::~PreScanOutputDev() { } void PreScanOutputDev::startPage(int pageNum, GfxState *state) { } void PreScanOutputDev::endPage() { } void PreScanOutputDev::stroke(GfxState *state) { double *dash; int dashLen; double dashStart; check(state->getStrokeColorSpace(), state->getStrokeColor(), state->getStrokeOpacity(), state->getBlendMode()); state->getLineDash(&dash, &dashLen, &dashStart); if (dashLen != 0) { gdi = gFalse; } } void PreScanOutputDev::fill(GfxState *state) { check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); } void PreScanOutputDev::eoFill(GfxState *state) { check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); } void PreScanOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) { if (paintType == 1) { gfx->drawForm(str, resDict, mat, bbox); } else { check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); } } GBool PreScanOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) { if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) { gray = gFalse; } mono = gFalse; if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) { transparency = gTrue; } return gTrue; } GBool PreScanOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) { gray = gFalse; } mono = gFalse; if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) { transparency = gTrue; } return gTrue; } GBool PreScanOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { if (shading->getColorSpace()->getMode() != csDeviceGray && shading->getColorSpace()->getMode() != csCalGray) { gray = gFalse; } mono = gFalse; if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) { transparency = gTrue; } return gTrue; } void PreScanOutputDev::clip(GfxState *state) { //~ check for a rectangle "near" the edge of the page; //~ else set gdi to false } void PreScanOutputDev::eoClip(GfxState *state) { //~ see clip() } void PreScanOutputDev::beginStringOp(GfxState *state) { int render; GfxFont *font; double m11, m12, m21, m22; GBool simpleTTF; render = state->getRender(); if (!(render & 1)) { check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); } if ((render & 3) == 1 || (render & 3) == 2) { check(state->getStrokeColorSpace(), state->getStrokeColor(), state->getStrokeOpacity(), state->getBlendMode()); } font = state->getFont(); state->getFontTransMat(&m11, &m12, &m21, &m22); //~ this should check for external fonts that are non-TrueType simpleTTF = fabs(m11 + m22) < 0.01 && m11 > 0 && fabs(m12) < 0.01 && fabs(m21) < 0.01 && fabs(state->getHorizScaling() - 1) < 0.001 && (font->getType() == fontTrueType || font->getType() == fontTrueTypeOT); if (simpleTTF) { //~ need to create a FoFiTrueType object, and check for a Unicode cmap } if (state->getRender() != 0 || !simpleTTF) { gdi = gFalse; } } void PreScanOutputDev::endStringOp(GfxState *state) { } GBool PreScanOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { // return false so all Type 3 chars get rendered (no caching) return gFalse; } void PreScanOutputDev::endType3Char(GfxState *state) { } void PreScanOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { int i, j; check(state->getFillColorSpace(), state->getFillColor(), state->getFillOpacity(), state->getBlendMode()); if (state->getFillColorSpace()->getMode() == csPattern) { patternImgMask = gTrue; } gdi = gFalse; if (inlineImg) { str->reset(); j = height * ((width + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); str->close(); } } void PreScanOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { GfxColorSpace *colorSpace; int i, j; colorSpace = colorMap->getColorSpace(); if (colorSpace->getMode() == csIndexed) { colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); } if (colorSpace->getMode() == csDeviceGray || colorSpace->getMode() == csCalGray) { if (colorMap->getBits() > 1) { mono = gFalse; } } else { gray = gFalse; mono = gFalse; } if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) { transparency = gTrue; } gdi = gFalse; if (inlineImg) { str->reset(); j = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); str->close(); } } void PreScanOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { GfxColorSpace *colorSpace; colorSpace = colorMap->getColorSpace(); if (colorSpace->getMode() == csIndexed) { colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); } if (colorSpace->getMode() == csDeviceGray || colorSpace->getMode() == csCalGray) { if (colorMap->getBits() > 1) { mono = gFalse; } } else { gray = gFalse; mono = gFalse; } if (state->getFillOpacity() != 1 || state->getBlendMode() != gfxBlendNormal) { transparency = gTrue; } gdi = gFalse; } void PreScanOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap) { GfxColorSpace *colorSpace; colorSpace = colorMap->getColorSpace(); if (colorSpace->getMode() == csIndexed) { colorSpace = ((GfxIndexedColorSpace *)colorSpace)->getBase(); } if (colorSpace->getMode() != csDeviceGray && colorSpace->getMode() != csCalGray) { gray = gFalse; } mono = gFalse; transparency = gTrue; gdi = gFalse; } void PreScanOutputDev::beginTransparencyGroup( GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask) { transparency = gTrue; gdi = gFalse; } void PreScanOutputDev::check(GfxColorSpace *colorSpace, GfxColor *color, double opacity, GfxBlendMode blendMode) { GfxRGB rgb; if (colorSpace->getMode() == csPattern) { mono = gFalse; gray = gFalse; gdi = gFalse; } else { colorSpace->getRGB(color, &rgb); if (rgb.r != rgb.g || rgb.g != rgb.b || rgb.b != rgb.r) { mono = gFalse; gray = gFalse; } else if (!((rgb.r == 0 && rgb.g == 0 && rgb.b == 0) || (rgb.r == gfxColorComp1 && rgb.g == gfxColorComp1 && rgb.b == gfxColorComp1))) { mono = gFalse; } } if (opacity != 1 || blendMode != gfxBlendNormal) { transparency = gTrue; } } void PreScanOutputDev::clearStats() { mono = gTrue; gray = gTrue; transparency = gFalse; patternImgMask = gFalse; gdi = gTrue; } xpdf-3.03/xpdf/Array.h0000644000076400007640000000214711622305345014107 0ustar dereknderekn//======================================================================== // // Array.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ARRAY_H #define ARRAY_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" class XRef; //------------------------------------------------------------------------ // Array //------------------------------------------------------------------------ class Array { public: // Constructor. Array(XRef *xrefA); // Destructor. ~Array(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get number of elements. int getLength() { return length; } // Add an element. void add(Object *elem); // Accessors. Object *get(int i, Object *obj); Object *getNF(int i, Object *obj); private: XRef *xref; // the xref table for this PDF file Object *elems; // array of elements int size; // size of array int length; // number of elements in array int ref; // reference count }; #endif xpdf-3.03/xpdf/xpdf.cc0000644000076400007640000002446111622305345014133 0ustar dereknderekn//======================================================================== // // xpdf.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #include "gtypes.h" #include "GString.h" #include "parseargs.h" #include "gfile.h" #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "XPDFApp.h" #include "config.h" //------------------------------------------------------------------------ // command line options //------------------------------------------------------------------------ static GBool contView = gFalse; static char enableT1libStr[16] = ""; static char enableFreeTypeStr[16] = ""; static char antialiasStr[16] = ""; static char vectorAntialiasStr[16] = ""; static char psFileArg[256]; static char paperSize[15] = ""; static int paperWidth = 0; static int paperHeight = 0; static GBool level1 = gFalse; static char textEncName[128] = ""; static char textEOL[16] = ""; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static GBool fullScreen = gFalse; static char remoteName[100] = "xpdf_"; static char remoteCmd[512] = ""; static GBool doRemoteReload = gFalse; static GBool doRemoteRaise = gFalse; static GBool doRemoteQuit = gFalse; static GBool printCommands = gFalse; static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-g", argStringDummy, NULL, 0, "initial window geometry"}, {"-geometry", argStringDummy, NULL, 0, "initial window geometry"}, {"-title", argStringDummy, NULL, 0, "window title"}, {"-cmap", argFlagDummy, NULL, 0, "install a private colormap"}, {"-rgb", argIntDummy, NULL, 0, "biggest RGB cube to allocate (default is 5)"}, {"-rv", argFlagDummy, NULL, 0, "reverse video"}, {"-papercolor", argStringDummy, NULL, 0, "color of paper background"}, {"-z", argStringDummy, NULL, 0, "initial zoom level (percent, 'page', 'width')"}, {"-cont", argFlag, &contView, 0, "start in continuous view mode" }, #if HAVE_T1LIB_H {"-t1lib", argString, enableT1libStr, sizeof(enableT1libStr), "enable t1lib font rasterizer: yes, no"}, #endif #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H {"-freetype", argString, enableFreeTypeStr, sizeof(enableFreeTypeStr), "enable FreeType font rasterizer: yes, no"}, #endif {"-aa", argString, antialiasStr, sizeof(antialiasStr), "enable font anti-aliasing: yes, no"}, {"-aaVector", argString, vectorAntialiasStr, sizeof(vectorAntialiasStr), "enable vector anti-aliasing: yes, no"}, {"-ps", argString, psFileArg, sizeof(psFileArg), "default PostScript file name or command"}, {"-paper", argString, paperSize, sizeof(paperSize), "paper size (letter, legal, A4, A3, match)"}, {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, {"-paperh", argInt, &paperHeight, 0, "paper height, in points"}, {"-level1", argFlag, &level1, 0, "generate Level 1 PostScript"}, {"-enc", argString, textEncName, sizeof(textEncName), "output text encoding name"}, {"-eol", argString, textEOL, sizeof(textEOL), "output end-of-line convention (unix, dos, or mac)"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-fullscreen", argFlag, &fullScreen, 0, "run in full-screen (presentation) mode"}, {"-remote", argString, remoteName + 5, sizeof(remoteName) - 5, "start/contact xpdf remote server with specified name"}, {"-exec", argString, remoteCmd, sizeof(remoteCmd), "execute command on xpdf remote server (with -remote only)"}, {"-reload", argFlag, &doRemoteReload, 0, "reload xpdf remote server window (with -remote only)"}, {"-raise", argFlag, &doRemoteRaise, 0, "raise xpdf remote server window (with -remote only)"}, {"-quit", argFlag, &doRemoteQuit, 0, "kill xpdf remote server (with -remote only)"}, {"-cmd", argFlag, &printCommands, 0, "print commands as they're executed"}, {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; //------------------------------------------------------------------------ int main(int argc, char *argv[]) { XPDFApp *app; GString *fileName; int pg; GString *destName; GString *userPasswordStr, *ownerPasswordStr; GBool ok; int exitCode; exitCode = 0; userPasswordStr = ownerPasswordStr = NULL; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || printVersion || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("xpdf", "[ [ | +]]", argDesc); } exitCode = 99; goto done0; } // read config file globalParams = new GlobalParams(cfgFileName); globalParams->setupBaseFonts(NULL); if (contView) { globalParams->setContinuousView(contView); } if (psFileArg[0]) { globalParams->setPSFile(psFileArg); } if (paperSize[0]) { if (!globalParams->setPSPaperSize(paperSize)) { fprintf(stderr, "Invalid paper size\n"); } } else { if (paperWidth) { globalParams->setPSPaperWidth(paperWidth); } if (paperHeight) { globalParams->setPSPaperHeight(paperHeight); } } if (level1) { globalParams->setPSLevel(psLevel1); } if (textEncName[0]) { globalParams->setTextEncoding(textEncName); } if (textEOL[0]) { if (!globalParams->setTextEOL(textEOL)) { fprintf(stderr, "Bad '-eol' value on command line\n"); } } if (enableT1libStr[0]) { if (!globalParams->setEnableT1lib(enableT1libStr)) { fprintf(stderr, "Bad '-t1lib' value on command line\n"); } } if (enableFreeTypeStr[0]) { if (!globalParams->setEnableFreeType(enableFreeTypeStr)) { fprintf(stderr, "Bad '-freetype' value on command line\n"); } } if (antialiasStr[0]) { if (!globalParams->setAntialias(antialiasStr)) { fprintf(stderr, "Bad '-aa' value on command line\n"); } } if (vectorAntialiasStr[0]) { if (!globalParams->setVectorAntialias(vectorAntialiasStr)) { fprintf(stderr, "Bad '-aaVector' value on command line\n"); } } if (printCommands) { globalParams->setPrintCommands(printCommands); } if (quiet) { globalParams->setErrQuiet(quiet); } // create the XPDFApp object app = new XPDFApp(&argc, argv); // the initialZoom parameter can be set in either the config file or // as an X resource (or command line arg) if (app->getInitialZoom()) { globalParams->setInitialZoom(app->getInitialZoom()->getCString()); } // check command line ok = ok && argc >= 1 && argc <= 3; if (remoteCmd[0]) { ok = ok && remoteName[5] && !doRemoteReload && !doRemoteRaise && !doRemoteQuit && argc == 1; } if (doRemoteReload) { ok = ok && remoteName[5] && !doRemoteQuit && argc == 1; } if (doRemoteRaise) { ok = ok && remoteName[5] && !doRemoteQuit; } if (doRemoteQuit) { ok = ok && remoteName[5] && argc == 1; } if (!ok || printVersion || printHelp) { fprintf(stderr, "xpdf version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("xpdf", "[ [ | +]]", argDesc); } exitCode = 99; goto done1; } if (argc >= 2) { fileName = new GString(argv[1]); } else { fileName = NULL; } pg = 1; destName = NULL; if (argc == 3) { if (argv[2][0] == '+') { destName = new GString(&argv[2][1]); } else { pg = atoi(argv[2]); if (pg < 0) { fprintf(stderr, "Invalid page number (%d)\n", pg); exitCode = 99; goto done2; } } } // handle remote server stuff if (remoteName[5]) { app->setRemoteName(remoteName); if (app->remoteServerRunning()) { if (fileName) { if (destName) { app->remoteOpenAtDest(fileName, destName, doRemoteRaise); } else { app->remoteOpen(fileName, pg, doRemoteRaise); } } else if (remoteCmd[0]) { app->remoteExec(remoteCmd); } else if (doRemoteReload) { app->remoteReload(doRemoteRaise); } else if (doRemoteRaise) { app->remoteRaise(); } else if (doRemoteQuit) { app->remoteQuit(); } goto done2; } if (doRemoteQuit) { goto done2; } } // set options app->setFullScreen(fullScreen); // check for password string(s) ownerPasswordStr = ownerPassword[0] != '\001' ? new GString(ownerPassword) : (GString *)NULL; userPasswordStr = userPassword[0] != '\001' ? new GString(userPassword) : (GString *)NULL; // open the file and run the main loop if (destName) { if (!app->openAtDest(fileName, destName, ownerPasswordStr, userPasswordStr)) { exitCode = 1; goto done2; } } else { if (!app->open(fileName, pg, ownerPasswordStr, userPasswordStr)) { exitCode = 1; goto done2; } } app->run(); exitCode = 0; // clean up done2: if (userPasswordStr) { delete userPasswordStr; } if (ownerPasswordStr) { delete ownerPasswordStr; } if (destName) { delete destName; } if (fileName) { delete fileName; } done1: delete app; delete globalParams; // check for memory leaks done0: Object::memCheck(stderr); gMemReport(stderr); return exitCode; } xpdf-3.03/xpdf/Dict.cc0000644000076400007640000000360411622305345014051 0ustar dereknderekn//======================================================================== // // Dict.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "Object.h" #include "XRef.h" #include "Dict.h" //------------------------------------------------------------------------ // Dict //------------------------------------------------------------------------ Dict::Dict(XRef *xrefA) { xref = xrefA; entries = NULL; size = length = 0; ref = 1; } Dict::~Dict() { int i; for (i = 0; i < length; ++i) { gfree(entries[i].key); entries[i].val.free(); } gfree(entries); } void Dict::add(char *key, Object *val) { if (length == size) { if (length == 0) { size = 8; } else { size *= 2; } entries = (DictEntry *)greallocn(entries, size, sizeof(DictEntry)); } entries[length].key = key; entries[length].val = *val; ++length; } inline DictEntry *Dict::find(const char *key) { int i; for (i = 0; i < length; ++i) { if (!strcmp(key, entries[i].key)) return &entries[i]; } return NULL; } GBool Dict::is(const char *type) { DictEntry *e; return (e = find("Type")) && e->val.isName(type); } Object *Dict::lookup(const char *key, Object *obj, int recursion) { DictEntry *e; return (e = find(key)) ? e->val.fetch(xref, obj, recursion) : obj->initNull(); } Object *Dict::lookupNF(const char *key, Object *obj) { DictEntry *e; return (e = find(key)) ? e->val.copy(obj) : obj->initNull(); } char *Dict::getKey(int i) { return entries[i].key; } Object *Dict::getVal(int i, Object *obj) { return entries[i].val.fetch(xref, obj); } Object *Dict::getValNF(int i, Object *obj) { return entries[i].val.copy(obj); } xpdf-3.03/xpdf/dblLeftArrow.xbm0000644000076400007640000000045011622305345015752 0ustar dereknderekn#define dblLeftArrow_width 16 #define dblLeftArrow_height 15 static unsigned char dblLeftArrow_bits[] = { 0x80, 0x80, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, 0xfe, 0xfe, 0xff, 0xff, 0xfe, 0xfe, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0x80, 0x80}; xpdf-3.03/xpdf/UnicodeMapTables.h0000644000076400007640000002635511622305345016217 0ustar dereknderekn//======================================================================== // // UnicodeMapTables.h // // Copyright 2001-2009 Glyph & Cog, LLC // //======================================================================== static UnicodeMapRange latin1UnicodeMapRanges[] = { { 0x000a, 0x000a, 0x0a, 1 }, { 0x000c, 0x000d, 0x0c, 1 }, { 0x0020, 0x007e, 0x20, 1 }, { 0x00a0, 0x00a0, 0x20, 1 }, { 0x00a1, 0x00ac, 0xa1, 1 }, { 0x00ae, 0x00ff, 0xae, 1 }, { 0x010c, 0x010c, 0x43, 1 }, { 0x010d, 0x010d, 0x63, 1 }, { 0x0131, 0x0131, 0x69, 1 }, { 0x0141, 0x0141, 0x4c, 1 }, { 0x0142, 0x0142, 0x6c, 1 }, { 0x0152, 0x0152, 0x4f45, 2 }, { 0x0153, 0x0153, 0x6f65, 2 }, { 0x0160, 0x0160, 0x53, 1 }, { 0x0161, 0x0161, 0x73, 1 }, { 0x0178, 0x0178, 0x59, 1 }, { 0x017d, 0x017d, 0x5a, 1 }, { 0x017e, 0x017e, 0x7a, 1 }, { 0x02c6, 0x02c6, 0x5e, 1 }, { 0x02da, 0x02da, 0xb0, 1 }, { 0x02dc, 0x02dc, 0x7e, 1 }, { 0x2013, 0x2013, 0xad, 1 }, { 0x2014, 0x2014, 0x2d2d, 2 }, { 0x2018, 0x2018, 0x60, 1 }, { 0x2019, 0x2019, 0x27, 1 }, { 0x201a, 0x201a, 0x2c, 1 }, { 0x201c, 0x201c, 0x22, 1 }, { 0x201d, 0x201d, 0x22, 1 }, { 0x201e, 0x201e, 0x2c2c, 2 }, { 0x2022, 0x2022, 0xb7, 1 }, { 0x2026, 0x2026, 0x2e2e2e, 3 }, { 0x2039, 0x2039, 0x3c, 1 }, { 0x203a, 0x203a, 0x3e, 1 }, { 0x2044, 0x2044, 0x2f, 1 }, { 0x2122, 0x2122, 0x544d, 2 }, { 0x2212, 0x2212, 0x2d, 1 }, { 0xf6f9, 0xf6f9, 0x4c, 1 }, { 0xf6fa, 0xf6fa, 0x4f45, 2 }, { 0xf6fc, 0xf6fc, 0xb0, 1 }, { 0xf6fd, 0xf6fd, 0x53, 1 }, { 0xf6fe, 0xf6fe, 0x7e, 1 }, { 0xf6ff, 0xf6ff, 0x5a, 1 }, { 0xf721, 0xf721, 0x21, 1 }, { 0xf724, 0xf724, 0x24, 1 }, { 0xf726, 0xf726, 0x26, 1 }, { 0xf730, 0xf739, 0x30, 1 }, { 0xf73f, 0xf73f, 0x3f, 1 }, { 0xf761, 0xf77a, 0x41, 1 }, { 0xf7a1, 0xf7a2, 0xa1, 1 }, { 0xf7bf, 0xf7bf, 0xbf, 1 }, { 0xf7e0, 0xf7f6, 0xc0, 1 }, { 0xf7f8, 0xf7fe, 0xd8, 1 }, { 0xf7ff, 0xf7ff, 0x59, 1 }, { 0xfb00, 0xfb00, 0x6666, 2 }, { 0xfb01, 0xfb01, 0x6669, 2 }, { 0xfb02, 0xfb02, 0x666c, 2 }, { 0xfb03, 0xfb03, 0x666669, 3 }, { 0xfb04, 0xfb04, 0x66666c, 3 }, { 0xfb05, 0xfb05, 0x7374, 2 }, { 0xfb06, 0xfb06, 0x7374, 2 } }; #define latin1UnicodeMapLen (sizeof(latin1UnicodeMapRanges) / sizeof(UnicodeMapRange)) static UnicodeMapRange ascii7UnicodeMapRanges[] = { { 0x000a, 0x000a, 0x0a, 1 }, { 0x000c, 0x000d, 0x0c, 1 }, { 0x0020, 0x005f, 0x20, 1 }, { 0x0061, 0x007e, 0x61, 1 }, { 0x00a6, 0x00a6, 0x7c, 1 }, { 0x00a9, 0x00a9, 0x286329, 3 }, { 0x00ae, 0x00ae, 0x285229, 3 }, { 0x00b7, 0x00b7, 0x2a, 1 }, { 0x00bc, 0x00bc, 0x312f34, 3 }, { 0x00bd, 0x00bd, 0x312f32, 3 }, { 0x00be, 0x00be, 0x332f34, 3 }, { 0x00c0, 0x00c0, 0x41, 1 }, { 0x00c1, 0x00c1, 0x41, 1 }, { 0x00c2, 0x00c2, 0x41, 1 }, { 0x00c3, 0x00c3, 0x41, 1 }, { 0x00c4, 0x00c4, 0x41, 1 }, { 0x00c5, 0x00c5, 0x41, 1 }, { 0x00c6, 0x00c6, 0x4145, 2 }, { 0x00c7, 0x00c7, 0x43, 1 }, { 0x00c8, 0x00c8, 0x45, 1 }, { 0x00c9, 0x00c9, 0x45, 1 }, { 0x00ca, 0x00ca, 0x45, 1 }, { 0x00cb, 0x00cb, 0x45, 1 }, { 0x00cc, 0x00cc, 0x49, 1 }, { 0x00cd, 0x00cd, 0x49, 1 }, { 0x00ce, 0x00ce, 0x49, 1 }, { 0x00cf, 0x00cf, 0x49, 1 }, { 0x00d1, 0x00d2, 0x4e, 1 }, { 0x00d3, 0x00d3, 0x4f, 1 }, { 0x00d4, 0x00d4, 0x4f, 1 }, { 0x00d5, 0x00d5, 0x4f, 1 }, { 0x00d6, 0x00d6, 0x4f, 1 }, { 0x00d7, 0x00d7, 0x78, 1 }, { 0x00d8, 0x00d8, 0x4f, 1 }, { 0x00d9, 0x00d9, 0x55, 1 }, { 0x00da, 0x00da, 0x55, 1 }, { 0x00db, 0x00db, 0x55, 1 }, { 0x00dc, 0x00dc, 0x55, 1 }, { 0x00dd, 0x00dd, 0x59, 1 }, { 0x00e0, 0x00e0, 0x61, 1 }, { 0x00e1, 0x00e1, 0x61, 1 }, { 0x00e2, 0x00e2, 0x61, 1 }, { 0x00e3, 0x00e3, 0x61, 1 }, { 0x00e4, 0x00e4, 0x61, 1 }, { 0x00e5, 0x00e5, 0x61, 1 }, { 0x00e6, 0x00e6, 0x6165, 2 }, { 0x00e7, 0x00e7, 0x63, 1 }, { 0x00e8, 0x00e8, 0x65, 1 }, { 0x00e9, 0x00e9, 0x65, 1 }, { 0x00ea, 0x00ea, 0x65, 1 }, { 0x00eb, 0x00eb, 0x65, 1 }, { 0x00ec, 0x00ec, 0x69, 1 }, { 0x00ed, 0x00ed, 0x69, 1 }, { 0x00ee, 0x00ee, 0x69, 1 }, { 0x00ef, 0x00ef, 0x69, 1 }, { 0x00f1, 0x00f2, 0x6e, 1 }, { 0x00f3, 0x00f3, 0x6f, 1 }, { 0x00f4, 0x00f4, 0x6f, 1 }, { 0x00f5, 0x00f5, 0x6f, 1 }, { 0x00f6, 0x00f6, 0x6f, 1 }, { 0x00f7, 0x00f7, 0x2f, 1 }, { 0x00f8, 0x00f8, 0x6f, 1 }, { 0x00f9, 0x00f9, 0x75, 1 }, { 0x00fa, 0x00fa, 0x75, 1 }, { 0x00fb, 0x00fb, 0x75, 1 }, { 0x00fc, 0x00fc, 0x75, 1 }, { 0x00fd, 0x00fd, 0x79, 1 }, { 0x00ff, 0x00ff, 0x79, 1 }, { 0x0131, 0x0131, 0x69, 1 }, { 0x0141, 0x0141, 0x4c, 1 }, { 0x0152, 0x0152, 0x4f45, 2 }, { 0x0153, 0x0153, 0x6f65, 2 }, { 0x0160, 0x0160, 0x53, 1 }, { 0x0178, 0x0178, 0x59, 1 }, { 0x017d, 0x017d, 0x5a, 1 }, { 0x2013, 0x2013, 0x2d, 1 }, { 0x2014, 0x2014, 0x2d2d, 2 }, { 0x2018, 0x2018, 0x60, 1 }, { 0x2019, 0x2019, 0x27, 1 }, { 0x201c, 0x201c, 0x22, 1 }, { 0x201d, 0x201d, 0x22, 1 }, { 0x2022, 0x2022, 0x2a, 1 }, { 0x2026, 0x2026, 0x2e2e2e, 3 }, { 0x2122, 0x2122, 0x544d, 2 }, { 0x2212, 0x2212, 0x2d, 1 }, { 0xf6f9, 0xf6f9, 0x4c, 1 }, { 0xf6fa, 0xf6fa, 0x4f45, 2 }, { 0xf6fd, 0xf6fd, 0x53, 1 }, { 0xf6fe, 0xf6fe, 0x7e, 1 }, { 0xf6ff, 0xf6ff, 0x5a, 1 }, { 0xf721, 0xf721, 0x21, 1 }, { 0xf724, 0xf724, 0x24, 1 }, { 0xf726, 0xf726, 0x26, 1 }, { 0xf730, 0xf739, 0x30, 1 }, { 0xf73f, 0xf73f, 0x3f, 1 }, { 0xf761, 0xf77a, 0x41, 1 }, { 0xf7e0, 0xf7e0, 0x41, 1 }, { 0xf7e1, 0xf7e1, 0x41, 1 }, { 0xf7e2, 0xf7e2, 0x41, 1 }, { 0xf7e3, 0xf7e3, 0x41, 1 }, { 0xf7e4, 0xf7e4, 0x41, 1 }, { 0xf7e5, 0xf7e5, 0x41, 1 }, { 0xf7e6, 0xf7e6, 0x4145, 2 }, { 0xf7e7, 0xf7e7, 0x43, 1 }, { 0xf7e8, 0xf7e8, 0x45, 1 }, { 0xf7e9, 0xf7e9, 0x45, 1 }, { 0xf7ea, 0xf7ea, 0x45, 1 }, { 0xf7eb, 0xf7eb, 0x45, 1 }, { 0xf7ec, 0xf7ec, 0x49, 1 }, { 0xf7ed, 0xf7ed, 0x49, 1 }, { 0xf7ee, 0xf7ee, 0x49, 1 }, { 0xf7ef, 0xf7ef, 0x49, 1 }, { 0xf7f1, 0xf7f2, 0x4e, 1 }, { 0xf7f3, 0xf7f3, 0x4f, 1 }, { 0xf7f4, 0xf7f4, 0x4f, 1 }, { 0xf7f5, 0xf7f5, 0x4f, 1 }, { 0xf7f6, 0xf7f6, 0x4f, 1 }, { 0xf7f8, 0xf7f8, 0x4f, 1 }, { 0xf7f9, 0xf7f9, 0x55, 1 }, { 0xf7fa, 0xf7fa, 0x55, 1 }, { 0xf7fb, 0xf7fb, 0x55, 1 }, { 0xf7fc, 0xf7fc, 0x55, 1 }, { 0xf7fd, 0xf7fd, 0x59, 1 }, { 0xf7ff, 0xf7ff, 0x59, 1 }, { 0xfb00, 0xfb00, 0x6666, 2 }, { 0xfb01, 0xfb01, 0x6669, 2 }, { 0xfb02, 0xfb02, 0x666c, 2 }, { 0xfb03, 0xfb03, 0x666669, 3 }, { 0xfb04, 0xfb04, 0x66666c, 3 }, { 0xfb05, 0xfb05, 0x7374, 2 }, { 0xfb06, 0xfb06, 0x7374, 2 } }; #define ascii7UnicodeMapLen (sizeof(ascii7UnicodeMapRanges) / sizeof(UnicodeMapRange)) static UnicodeMapRange symbolUnicodeMapRanges[] = { { 0x0020, 0x0021, 0x20, 1 }, { 0x0023, 0x0023, 0x23, 1 }, { 0x0025, 0x0026, 0x25, 1 }, { 0x0028, 0x0029, 0x28, 1 }, { 0x002b, 0x002c, 0x2b, 1 }, { 0x002e, 0x003f, 0x2e, 1 }, { 0x005b, 0x005b, 0x5b, 1 }, { 0x005d, 0x005d, 0x5d, 1 }, { 0x005f, 0x005f, 0x5f, 1 }, { 0x007b, 0x007d, 0x7b, 1 }, { 0x00ac, 0x00ac, 0xd8, 1 }, { 0x00b0, 0x00b1, 0xb0, 1 }, { 0x00b5, 0x00b5, 0x6d, 1 }, { 0x00d7, 0x00d7, 0xb4, 1 }, { 0x00f7, 0x00f7, 0xb8, 1 }, { 0x0192, 0x0192, 0xa6, 1 }, { 0x0391, 0x0392, 0x41, 1 }, { 0x0393, 0x0393, 0x47, 1 }, { 0x0395, 0x0395, 0x45, 1 }, { 0x0396, 0x0396, 0x5a, 1 }, { 0x0397, 0x0397, 0x48, 1 }, { 0x0398, 0x0398, 0x51, 1 }, { 0x0399, 0x0399, 0x49, 1 }, { 0x039a, 0x039d, 0x4b, 1 }, { 0x039e, 0x039e, 0x58, 1 }, { 0x039f, 0x03a0, 0x4f, 1 }, { 0x03a1, 0x03a1, 0x52, 1 }, { 0x03a3, 0x03a5, 0x53, 1 }, { 0x03a6, 0x03a6, 0x46, 1 }, { 0x03a7, 0x03a7, 0x43, 1 }, { 0x03a8, 0x03a8, 0x59, 1 }, { 0x03b1, 0x03b2, 0x61, 1 }, { 0x03b3, 0x03b3, 0x67, 1 }, { 0x03b4, 0x03b5, 0x64, 1 }, { 0x03b6, 0x03b6, 0x7a, 1 }, { 0x03b7, 0x03b7, 0x68, 1 }, { 0x03b8, 0x03b8, 0x71, 1 }, { 0x03b9, 0x03b9, 0x69, 1 }, { 0x03ba, 0x03bb, 0x6b, 1 }, { 0x03bd, 0x03bd, 0x6e, 1 }, { 0x03be, 0x03be, 0x78, 1 }, { 0x03bf, 0x03c0, 0x6f, 1 }, { 0x03c1, 0x03c1, 0x72, 1 }, { 0x03c2, 0x03c2, 0x56, 1 }, { 0x03c3, 0x03c5, 0x73, 1 }, { 0x03c6, 0x03c6, 0x66, 1 }, { 0x03c7, 0x03c7, 0x63, 1 }, { 0x03c8, 0x03c8, 0x79, 1 }, { 0x03c9, 0x03c9, 0x77, 1 }, { 0x03d1, 0x03d1, 0x4a, 1 }, { 0x03d2, 0x03d2, 0xa1, 1 }, { 0x03d5, 0x03d5, 0x6a, 1 }, { 0x03d6, 0x03d6, 0x76, 1 }, { 0x2022, 0x2022, 0xb7, 1 }, { 0x2026, 0x2026, 0xbc, 1 }, { 0x2032, 0x2032, 0xa2, 1 }, { 0x2033, 0x2033, 0xb2, 1 }, { 0x2044, 0x2044, 0xa4, 1 }, { 0x2111, 0x2111, 0xc1, 1 }, { 0x2118, 0x2118, 0xc3, 1 }, { 0x211c, 0x211c, 0xc2, 1 }, { 0x2126, 0x2126, 0x57, 1 }, { 0x2135, 0x2135, 0xc0, 1 }, { 0x2190, 0x2193, 0xac, 1 }, { 0x2194, 0x2194, 0xab, 1 }, { 0x21b5, 0x21b5, 0xbf, 1 }, { 0x21d0, 0x21d3, 0xdc, 1 }, { 0x21d4, 0x21d4, 0xdb, 1 }, { 0x2200, 0x2200, 0x22, 1 }, { 0x2202, 0x2202, 0xb6, 1 }, { 0x2203, 0x2203, 0x24, 1 }, { 0x2205, 0x2205, 0xc6, 1 }, { 0x2206, 0x2206, 0x44, 1 }, { 0x2207, 0x2207, 0xd1, 1 }, { 0x2208, 0x2209, 0xce, 1 }, { 0x220b, 0x220b, 0x27, 1 }, { 0x220f, 0x220f, 0xd5, 1 }, { 0x2211, 0x2211, 0xe5, 1 }, { 0x2212, 0x2212, 0x2d, 1 }, { 0x2217, 0x2217, 0x2a, 1 }, { 0x221a, 0x221a, 0xd6, 1 }, { 0x221d, 0x221d, 0xb5, 1 }, { 0x221e, 0x221e, 0xa5, 1 }, { 0x2220, 0x2220, 0xd0, 1 }, { 0x2227, 0x2228, 0xd9, 1 }, { 0x2229, 0x222a, 0xc7, 1 }, { 0x222b, 0x222b, 0xf2, 1 }, { 0x2234, 0x2234, 0x5c, 1 }, { 0x223c, 0x223c, 0x7e, 1 }, { 0x2245, 0x2245, 0x40, 1 }, { 0x2248, 0x2248, 0xbb, 1 }, { 0x2260, 0x2261, 0xb9, 1 }, { 0x2264, 0x2264, 0xa3, 1 }, { 0x2265, 0x2265, 0xb3, 1 }, { 0x2282, 0x2282, 0xcc, 1 }, { 0x2283, 0x2283, 0xc9, 1 }, { 0x2284, 0x2284, 0xcb, 1 }, { 0x2286, 0x2286, 0xcd, 1 }, { 0x2287, 0x2287, 0xca, 1 }, { 0x2295, 0x2295, 0xc5, 1 }, { 0x2297, 0x2297, 0xc4, 1 }, { 0x22a5, 0x22a5, 0x5e, 1 }, { 0x22c5, 0x22c5, 0xd7, 1 }, { 0x2320, 0x2320, 0xf3, 1 }, { 0x2321, 0x2321, 0xf5, 1 }, { 0x2329, 0x2329, 0xe1, 1 }, { 0x232a, 0x232a, 0xf1, 1 }, { 0x25ca, 0x25ca, 0xe0, 1 }, { 0x2660, 0x2660, 0xaa, 1 }, { 0x2663, 0x2663, 0xa7, 1 }, { 0x2665, 0x2665, 0xa9, 1 }, { 0x2666, 0x2666, 0xa8, 1 }, { 0xf6d9, 0xf6d9, 0xd3, 1 }, { 0xf6da, 0xf6da, 0xd2, 1 }, { 0xf6db, 0xf6db, 0xd4, 1 }, { 0xf8e5, 0xf8e5, 0x60, 1 }, { 0xf8e6, 0xf8e7, 0xbd, 1 }, { 0xf8e8, 0xf8ea, 0xe2, 1 }, { 0xf8eb, 0xf8f4, 0xe6, 1 }, { 0xf8f5, 0xf8f5, 0xf4, 1 }, { 0xf8f6, 0xf8fe, 0xf6, 1 } }; #define symbolUnicodeMapLen (sizeof(symbolUnicodeMapRanges) / sizeof(UnicodeMapRange)) static UnicodeMapRange zapfDingbatsUnicodeMapRanges[] = { { 0x0020, 0x0020, 0x20, 1 }, { 0x2192, 0x2192, 0xd5, 1 }, { 0x2194, 0x2195, 0xd6, 1 }, { 0x2460, 0x2469, 0xac, 1 }, { 0x25a0, 0x25a0, 0x6e, 1 }, { 0x25b2, 0x25b2, 0x73, 1 }, { 0x25bc, 0x25bc, 0x74, 1 }, { 0x25c6, 0x25c6, 0x75, 1 }, { 0x25cf, 0x25cf, 0x6c, 1 }, { 0x25d7, 0x25d7, 0x77, 1 }, { 0x2605, 0x2605, 0x48, 1 }, { 0x260e, 0x260e, 0x25, 1 }, { 0x261b, 0x261b, 0x2a, 1 }, { 0x261e, 0x261e, 0x2b, 1 }, { 0x2660, 0x2660, 0xab, 1 }, { 0x2663, 0x2663, 0xa8, 1 }, { 0x2665, 0x2665, 0xaa, 1 }, { 0x2666, 0x2666, 0xa9, 1 }, { 0x2701, 0x2704, 0x21, 1 }, { 0x2706, 0x2709, 0x26, 1 }, { 0x270c, 0x2727, 0x2c, 1 }, { 0x2729, 0x274b, 0x49, 1 }, { 0x274d, 0x274d, 0x6d, 1 }, { 0x274f, 0x2752, 0x6f, 1 }, { 0x2756, 0x2756, 0x76, 1 }, { 0x2758, 0x275e, 0x78, 1 }, { 0x2761, 0x2767, 0xa1, 1 }, { 0x2776, 0x2794, 0xb6, 1 }, { 0x2798, 0x27af, 0xd8, 1 }, { 0x27b1, 0x27be, 0xf1, 1 } }; #define zapfDingbatsUnicodeMapLen (sizeof(zapfDingbatsUnicodeMapRanges) / sizeof(UnicodeMapRange)) xpdf-3.03/xpdf/Parser.h0000644000076400007640000000302711622305345014263 0ustar dereknderekn//======================================================================== // // Parser.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PARSER_H #define PARSER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Lexer.h" //------------------------------------------------------------------------ // Parser //------------------------------------------------------------------------ class Parser { public: // Constructor. Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA); // Destructor. ~Parser(); // Get the next object from the input stream. If is // true, do not parse compound objects (arrays, dictionaries, or // streams). Object *getObj(Object *obj, GBool simpleOnly = gFalse, Guchar *fileKey = NULL, CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0, int objNum = 0, int objGen = 0, int recursion = 0); // Get stream. Stream *getStream() { return lexer->getStream(); } // Get current position in file. int getPos() { return lexer->getPos(); } private: XRef *xref; // the xref table for this PDF file Lexer *lexer; // input stream GBool allowStreams; // parse stream objects? Object buf1, buf2; // next two tokens int inlineImg; // set when inline image data is encountered Stream *makeStream(Object *dict, Guchar *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, int recursion); void shift(); }; #endif xpdf-3.03/xpdf/Outline.cc0000644000076400007640000000727011622305345014610 0ustar dereknderekn//======================================================================== // // Outline.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "gmem.h" #include "GString.h" #include "GList.h" #include "Error.h" #include "Link.h" #include "PDFDocEncoding.h" #include "Outline.h" //------------------------------------------------------------------------ Outline::Outline(Object *outlineObj, XRef *xref) { Object first, last; items = NULL; if (!outlineObj->isDict()) { return; } outlineObj->dictLookupNF("First", &first); outlineObj->dictLookupNF("Last", &last); if (first.isRef() && last.isRef()) { items = OutlineItem::readItemList(&first, &last, xref); } first.free(); last.free(); } Outline::~Outline() { if (items) { deleteGList(items, OutlineItem); } } //------------------------------------------------------------------------ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { Object obj1; GString *s; int i; xref = xrefA; title = NULL; action = NULL; kids = NULL; if (dict->lookup("Title", &obj1)->isString()) { s = obj1.getString(); if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { titleLen = (s->getLength() - 2) / 2; title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { titleLen = s->getLength(); title = (Unicode *)gmallocn(titleLen, sizeof(Unicode)); for (i = 0; i < titleLen; ++i) { title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } } } else { titleLen = 0; } obj1.free(); if (!dict->lookup("Dest", &obj1)->isNull()) { action = LinkAction::parseDest(&obj1); } else { obj1.free(); if (!dict->lookup("A", &obj1)->isNull()) { action = LinkAction::parseAction(&obj1); } } obj1.free(); dict->lookupNF("First", &firstRef); dict->lookupNF("Last", &lastRef); dict->lookupNF("Next", &nextRef); startsOpen = gFalse; if (dict->lookup("Count", &obj1)->isInt()) { if (obj1.getInt() > 0) { startsOpen = gTrue; } } obj1.free(); } OutlineItem::~OutlineItem() { close(); if (title) { gfree(title); } if (action) { delete action; } firstRef.free(); lastRef.free(); nextRef.free(); } GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, XRef *xrefA) { GList *items; OutlineItem *item; Object obj; Object *p, *refObj; int i; items = new GList(); if (!firstItemRef->isRef() || !lastItemRef->isRef()) { return items; } p = firstItemRef; do { if (!p->fetch(xrefA, &obj)->isDict()) { obj.free(); break; } item = new OutlineItem(obj.getDict(), xrefA); obj.free(); items->append(item); if (p->getRefNum() == lastItemRef->getRef().num && p->getRefGen() == lastItemRef->getRef().gen) { break; } p = &item->nextRef; if (!p->isRef()) { break; } for (i = 0; i < items->getLength(); ++i) { refObj = (i == 0) ? firstItemRef : &((OutlineItem *)items->get(i - 1))->nextRef; if (refObj->getRefNum() == p->getRefNum() && refObj->getRefGen() == p->getRefGen()) { error(errSyntaxError, -1, "Loop detected in outline item list"); p = NULL; break; } } } while (p); return items; } void OutlineItem::open() { if (!kids) { kids = readItemList(&firstRef, &lastRef, xref); } } void OutlineItem::close() { if (kids) { deleteGList(kids, OutlineItem); kids = NULL; } } xpdf-3.03/xpdf/leftArrowDis.xbm0000644000076400007640000000031211622305345015765 0ustar dereknderekn#define leftArrowDis_width 8 #define leftArrowDis_height 15 static unsigned char leftArrowDis_bits[] = { 0x80, 0x40, 0xa0, 0x50, 0xa8, 0x54, 0xaa, 0x55, 0xaa, 0x54, 0xa8, 0x50, 0xa0, 0x40, 0x80}; xpdf-3.03/xpdf/Array.cc0000644000076400007640000000247311622305345014247 0ustar dereknderekn//======================================================================== // // Array.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "Object.h" #include "Array.h" //------------------------------------------------------------------------ // Array //------------------------------------------------------------------------ Array::Array(XRef *xrefA) { xref = xrefA; elems = NULL; size = length = 0; ref = 1; } Array::~Array() { int i; for (i = 0; i < length; ++i) elems[i].free(); gfree(elems); } void Array::add(Object *elem) { if (length == size) { if (length == 0) { size = 8; } else { size *= 2; } elems = (Object *)greallocn(elems, size, sizeof(Object)); } elems[length] = *elem; ++length; } Object *Array::get(int i, Object *obj) { if (i < 0 || i >= length) { #ifdef DEBUG_MEM abort(); #else return obj->initNull(); #endif } return elems[i].fetch(xref, obj); } Object *Array::getNF(int i, Object *obj) { if (i < 0 || i >= length) { #ifdef DEBUG_MEM abort(); #else return obj->initNull(); #endif } return elems[i].copy(obj); } xpdf-3.03/xpdf/UnicodeMap.cc0000644000076400007640000001417011622305345015212 0ustar dereknderekn//======================================================================== // // UnicodeMap.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "gfile.h" #include "GString.h" #include "GList.h" #include "Error.h" #include "GlobalParams.h" #include "UnicodeMap.h" //------------------------------------------------------------------------ #define maxExtCode 16 struct UnicodeMapExt { Unicode u; // Unicode char char code[maxExtCode]; Guint nBytes; }; //------------------------------------------------------------------------ UnicodeMap *UnicodeMap::parse(GString *encodingNameA) { FILE *f; UnicodeMap *map; UnicodeMapRange *range; UnicodeMapExt *eMap; int size, eMapsSize; char buf[256]; int line, nBytes, i, x; char *tok1, *tok2, *tok3; if (!(f = globalParams->getUnicodeMapFile(encodingNameA))) { error(errSyntaxError, -1, "Couldn't find unicodeMap file for the '{0:t}' encoding", encodingNameA); return NULL; } map = new UnicodeMap(encodingNameA->copy()); size = 8; map->ranges = (UnicodeMapRange *)gmallocn(size, sizeof(UnicodeMapRange)); eMapsSize = 0; line = 1; while (getLine(buf, sizeof(buf), f)) { if ((tok1 = strtok(buf, " \t\r\n")) && (tok2 = strtok(NULL, " \t\r\n"))) { if (!(tok3 = strtok(NULL, " \t\r\n"))) { tok3 = tok2; tok2 = tok1; } nBytes = (int)strlen(tok3) / 2; if (nBytes <= 4) { if (map->len == size) { size *= 2; map->ranges = (UnicodeMapRange *) greallocn(map->ranges, size, sizeof(UnicodeMapRange)); } range = &map->ranges[map->len]; sscanf(tok1, "%x", &range->start); sscanf(tok2, "%x", &range->end); sscanf(tok3, "%x", &range->code); range->nBytes = nBytes; ++map->len; } else if (tok2 == tok1) { if (map->eMapsLen == eMapsSize) { eMapsSize += 16; map->eMaps = (UnicodeMapExt *) greallocn(map->eMaps, eMapsSize, sizeof(UnicodeMapExt)); } eMap = &map->eMaps[map->eMapsLen]; sscanf(tok1, "%x", &eMap->u); for (i = 0; i < nBytes; ++i) { sscanf(tok3 + i*2, "%2x", &x); eMap->code[i] = (char)x; } eMap->nBytes = nBytes; ++map->eMapsLen; } else { error(errSyntaxError, -1, "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding", line, encodingNameA); } } else { error(errSyntaxError, -1, "Bad line ({0:d}) in unicodeMap file for the '{1:t}' encoding", line, encodingNameA); } ++line; } fclose(f); return map; } UnicodeMap::UnicodeMap(GString *encodingNameA) { encodingName = encodingNameA; unicodeOut = gFalse; kind = unicodeMapUser; ranges = NULL; len = 0; eMaps = NULL; eMapsLen = 0; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA, UnicodeMapRange *rangesA, int lenA) { encodingName = new GString(encodingNameA); unicodeOut = unicodeOutA; kind = unicodeMapResident; ranges = rangesA; len = lenA; eMaps = NULL; eMapsLen = 0; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } UnicodeMap::UnicodeMap(const char *encodingNameA, GBool unicodeOutA, UnicodeMapFunc funcA) { encodingName = new GString(encodingNameA); unicodeOut = unicodeOutA; kind = unicodeMapFunc; func = funcA; eMaps = NULL; eMapsLen = 0; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } UnicodeMap::~UnicodeMap() { delete encodingName; if (kind == unicodeMapUser && ranges) { gfree(ranges); } if (eMaps) { gfree(eMaps); } #if MULTITHREADED gDestroyMutex(&mutex); #endif } void UnicodeMap::incRefCnt() { #if MULTITHREADED gLockMutex(&mutex); #endif ++refCnt; #if MULTITHREADED gUnlockMutex(&mutex); #endif } void UnicodeMap::decRefCnt() { GBool done; #if MULTITHREADED gLockMutex(&mutex); #endif done = --refCnt == 0; #if MULTITHREADED gUnlockMutex(&mutex); #endif if (done) { delete this; } } GBool UnicodeMap::match(GString *encodingNameA) { return !encodingName->cmp(encodingNameA); } int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) { int a, b, m, n, i, j; Guint code; if (kind == unicodeMapFunc) { return (*func)(u, buf, bufSize); } a = 0; b = len; if (u >= ranges[a].start) { // invariant: ranges[a].start <= u < ranges[b].start while (b - a > 1) { m = (a + b) / 2; if (u >= ranges[m].start) { a = m; } else if (u < ranges[m].start) { b = m; } } if (u <= ranges[a].end) { n = ranges[a].nBytes; if (n > bufSize) { return 0; } code = ranges[a].code + (u - ranges[a].start); for (i = n - 1; i >= 0; --i) { buf[i] = (char)(code & 0xff); code >>= 8; } return n; } } for (i = 0; i < eMapsLen; ++i) { if (eMaps[i].u == u) { n = eMaps[i].nBytes; for (j = 0; j < n; ++j) { buf[j] = eMaps[i].code[j]; } return n; } } return 0; } //------------------------------------------------------------------------ UnicodeMapCache::UnicodeMapCache() { int i; for (i = 0; i < unicodeMapCacheSize; ++i) { cache[i] = NULL; } } UnicodeMapCache::~UnicodeMapCache() { int i; for (i = 0; i < unicodeMapCacheSize; ++i) { if (cache[i]) { cache[i]->decRefCnt(); } } } UnicodeMap *UnicodeMapCache::getUnicodeMap(GString *encodingName) { UnicodeMap *map; int i, j; if (cache[0] && cache[0]->match(encodingName)) { cache[0]->incRefCnt(); return cache[0]; } for (i = 1; i < unicodeMapCacheSize; ++i) { if (cache[i] && cache[i]->match(encodingName)) { map = cache[i]; for (j = i; j >= 1; --j) { cache[j] = cache[j - 1]; } cache[0] = map; map->incRefCnt(); return map; } } if ((map = UnicodeMap::parse(encodingName))) { if (cache[unicodeMapCacheSize - 1]) { cache[unicodeMapCacheSize - 1]->decRefCnt(); } for (j = unicodeMapCacheSize - 1; j >= 1; --j) { cache[j] = cache[j - 1]; } cache[0] = map; map->incRefCnt(); return map; } return NULL; } xpdf-3.03/xpdf/PDFDoc.h0000644000076400007640000001374211622305345014073 0ustar dereknderekn//======================================================================== // // PDFDoc.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PDFDOC_H #define PDFDOC_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "XRef.h" #include "Catalog.h" #include "Page.h" class GString; class BaseStream; class OutputDev; class Links; class LinkAction; class LinkDest; class Outline; class OptionalContent; class PDFCore; //------------------------------------------------------------------------ // PDFDoc //------------------------------------------------------------------------ class PDFDoc { public: PDFDoc(GString *fileNameA, GString *ownerPassword = NULL, GString *userPassword = NULL, PDFCore *coreA = NULL); #ifdef WIN32 PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword = NULL, GString *userPassword = NULL, PDFCore *coreA = NULL); #endif PDFDoc(BaseStream *strA, GString *ownerPassword = NULL, GString *userPassword = NULL, PDFCore *coreA = NULL); ~PDFDoc(); // Was PDF document successfully opened? GBool isOk() { return ok; } // Get the error code (if isOk() returns false). int getErrorCode() { return errCode; } // Get file name. GString *getFileName() { return fileName; } #ifdef WIN32 wchar_t *getFileNameU() { return fileNameU; } #endif // Get the xref table. XRef *getXRef() { return xref; } // Get catalog. Catalog *getCatalog() { return catalog; } // Get base stream. BaseStream *getBaseStream() { return str; } // Get page parameters. double getPageMediaWidth(int page) { return catalog->getPage(page)->getMediaWidth(); } double getPageMediaHeight(int page) { return catalog->getPage(page)->getMediaHeight(); } double getPageCropWidth(int page) { return catalog->getPage(page)->getCropWidth(); } double getPageCropHeight(int page) { return catalog->getPage(page)->getCropHeight(); } int getPageRotate(int page) { return catalog->getPage(page)->getRotate(); } // Get number of pages. int getNumPages() { return catalog->getNumPages(); } // Return the contents of the metadata stream, or NULL if there is // no metadata. GString *readMetadata() { return catalog->readMetadata(); } // Return the structure tree root object. Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); } // Display a page. void displayPage(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Display part of a page. void displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); // Find a page, given its object ID. Returns page number, or 0 if // not found. int findPage(int num, int gen) { return catalog->findPage(num, gen); } // Returns the links for the current page, transferring ownership to // the caller. Links *getLinks(int page); // Find a named destination. Returns the link destination, or // NULL if is not a destination. LinkDest *findDest(GString *name) { return catalog->findDest(name); } // Process the links for a page. void processLinks(OutputDev *out, int page); #ifndef DISABLE_OUTLINE // Return the outline object. Outline *getOutline() { return outline; } #endif // Return the OptionalContent object. OptionalContent *getOptionalContent() { return optContent; } // Is the file encrypted? GBool isEncrypted() { return xref->isEncrypted(); } // Check various permissions. GBool okToPrint(GBool ignoreOwnerPW = gFalse) { return xref->okToPrint(ignoreOwnerPW); } GBool okToChange(GBool ignoreOwnerPW = gFalse) { return xref->okToChange(ignoreOwnerPW); } GBool okToCopy(GBool ignoreOwnerPW = gFalse) { return xref->okToCopy(ignoreOwnerPW); } GBool okToAddNotes(GBool ignoreOwnerPW = gFalse) { return xref->okToAddNotes(ignoreOwnerPW); } // Is this document linearized? GBool isLinearized(); // Return the document's Info dictionary (if any). Object *getDocInfo(Object *obj) { return xref->getDocInfo(obj); } Object *getDocInfoNF(Object *obj) { return xref->getDocInfoNF(obj); } // Return the PDF version specified by the file. double getPDFVersion() { return pdfVersion; } // Save this file with another name. GBool saveAs(GString *name); // Return a pointer to the PDFCore object. PDFCore *getCore() { return core; } // Get the list of embedded files. int getNumEmbeddedFiles() { return catalog->getNumEmbeddedFiles(); } Unicode *getEmbeddedFileName(int idx) { return catalog->getEmbeddedFileName(idx); } int getEmbeddedFileNameLength(int idx) { return catalog->getEmbeddedFileNameLength(idx); } GBool saveEmbeddedFile(int idx, char *path); #ifdef WIN32 GBool saveEmbeddedFile(int idx, wchar_t *path, int pathLen); #endif char *getEmbeddedFileMem(int idx, int *size); private: GBool setup(GString *ownerPassword, GString *userPassword); GBool setup2(GString *ownerPassword, GString *userPassword, GBool repairXRef); void checkHeader(); GBool checkEncryption(GString *ownerPassword, GString *userPassword); GBool saveEmbeddedFile2(int idx, FILE *f); GString *fileName; #ifdef WIN32 wchar_t *fileNameU; #endif FILE *file; BaseStream *str; PDFCore *core; double pdfVersion; XRef *xref; Catalog *catalog; #ifndef DISABLE_OUTLINE Outline *outline; #endif OptionalContent *optContent; GBool ok; int errCode; }; #endif xpdf-3.03/xpdf/Page.cc0000644000076400007640000002650111622305345014043 0ustar dereknderekn//======================================================================== // // Page.cc // // Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "GlobalParams.h" #include "Object.h" #include "Array.h" #include "Dict.h" #include "PDFDoc.h" #include "XRef.h" #include "Link.h" #include "OutputDev.h" #ifndef PDF_PARSER_ONLY #include "Gfx.h" #include "GfxState.h" #include "Annot.h" #endif #include "Error.h" #include "Catalog.h" #include "Page.h" //------------------------------------------------------------------------ // PDFRectangle //------------------------------------------------------------------------ void PDFRectangle::clipTo(PDFRectangle *rect) { if (x1 < rect->x1) { x1 = rect->x1; } else if (x1 > rect->x2) { x1 = rect->x2; } if (x2 < rect->x1) { x2 = rect->x1; } else if (x2 > rect->x2) { x2 = rect->x2; } if (y1 < rect->y1) { y1 = rect->y1; } else if (y1 > rect->y2) { y1 = rect->y2; } if (y2 < rect->y1) { y2 = rect->y1; } else if (y2 > rect->y2) { y2 = rect->y2; } } //------------------------------------------------------------------------ // PageAttrs //------------------------------------------------------------------------ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { Object obj1; // get old/default values if (attrs) { mediaBox = attrs->mediaBox; cropBox = attrs->cropBox; haveCropBox = attrs->haveCropBox; rotate = attrs->rotate; attrs->resources.copy(&resources); } else { // set default MediaBox to 8.5" x 11" -- this shouldn't be necessary // but some (non-compliant) PDF files don't specify a MediaBox mediaBox.x1 = 0; mediaBox.y1 = 0; mediaBox.x2 = 612; mediaBox.y2 = 792; cropBox.x1 = cropBox.y1 = cropBox.x2 = cropBox.y2 = 0; haveCropBox = gFalse; rotate = 0; resources.initNull(); } // media box readBox(dict, "MediaBox", &mediaBox); // crop box if (readBox(dict, "CropBox", &cropBox)) { haveCropBox = gTrue; } if (!haveCropBox) { cropBox = mediaBox; } // other boxes bleedBox = cropBox; readBox(dict, "BleedBox", &bleedBox); trimBox = cropBox; readBox(dict, "TrimBox", &trimBox); artBox = cropBox; readBox(dict, "ArtBox", &artBox); // rotate dict->lookup("Rotate", &obj1); if (obj1.isInt()) { rotate = obj1.getInt(); } obj1.free(); while (rotate < 0) { rotate += 360; } while (rotate >= 360) { rotate -= 360; } // misc attributes dict->lookup("LastModified", &lastModified); dict->lookup("BoxColorInfo", &boxColorInfo); dict->lookup("Group", &group); dict->lookup("Metadata", &metadata); dict->lookup("PieceInfo", &pieceInfo); dict->lookup("SeparationInfo", &separationInfo); // resource dictionary dict->lookup("Resources", &obj1); if (obj1.isDict()) { resources.free(); obj1.copy(&resources); } obj1.free(); } PageAttrs::PageAttrs() { mediaBox.x1 = mediaBox.y1 = 0; mediaBox.x2 = mediaBox.y2 = 50; cropBox = mediaBox; haveCropBox = gFalse; bleedBox = cropBox; trimBox = cropBox; artBox = cropBox; rotate = 0; lastModified.initNull(); boxColorInfo.initNull(); group.initNull(); metadata.initNull(); pieceInfo.initNull(); separationInfo.initNull(); resources.initNull(); } PageAttrs::~PageAttrs() { lastModified.free(); boxColorInfo.free(); group.free(); metadata.free(); pieceInfo.free(); separationInfo.free(); resources.free(); } void PageAttrs::clipBoxes() { cropBox.clipTo(&mediaBox); bleedBox.clipTo(&mediaBox); trimBox.clipTo(&mediaBox); artBox.clipTo(&mediaBox); } GBool PageAttrs::readBox(Dict *dict, const char *key, PDFRectangle *box) { PDFRectangle tmp; double t; Object obj1, obj2; GBool ok; dict->lookup(key, &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 4) { ok = gTrue; obj1.arrayGet(0, &obj2); if (obj2.isNum()) { tmp.x1 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); obj1.arrayGet(1, &obj2); if (obj2.isNum()) { tmp.y1 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); obj1.arrayGet(2, &obj2); if (obj2.isNum()) { tmp.x2 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); obj1.arrayGet(3, &obj2); if (obj2.isNum()) { tmp.y2 = obj2.getNum(); } else { ok = gFalse; } obj2.free(); if (ok) { if (tmp.x1 > tmp.x2) { t = tmp.x1; tmp.x1 = tmp.x2; tmp.x2 = t; } if (tmp.y1 > tmp.y2) { t = tmp.y1; tmp.y1 = tmp.y2; tmp.y2 = t; } *box = tmp; } } else { ok = gFalse; } obj1.free(); return ok; } //------------------------------------------------------------------------ // Page //------------------------------------------------------------------------ Page::Page(PDFDoc *docA, int numA, Dict *pageDict, PageAttrs *attrsA) { ok = gTrue; doc = docA; xref = doc->getXRef(); num = numA; // get attributes attrs = attrsA; attrs->clipBoxes(); // annotations pageDict->lookupNF("Annots", &annots); if (!(annots.isRef() || annots.isArray() || annots.isNull())) { error(errSyntaxError, -1, "Page annotations object (page {0:d}) is wrong type ({1:s})", num, annots.getTypeName()); annots.free(); goto err2; } // contents pageDict->lookupNF("Contents", &contents); if (!(contents.isRef() || contents.isArray() || contents.isNull())) { error(errSyntaxError, -1, "Page contents object (page {0:d}) is wrong type ({1:s})", num, contents.getTypeName()); contents.free(); goto err1; } return; err2: annots.initNull(); err1: contents.initNull(); ok = gFalse; } Page::Page(PDFDoc *docA, int numA) { doc = docA; xref = doc->getXRef(); num = numA; attrs = new PageAttrs(); annots.initNull(); contents.initNull(); ok = gTrue; } Page::~Page() { delete attrs; annots.free(); contents.free(); } Links *Page::getLinks() { Links *links; Object obj; links = new Links(getAnnots(&obj), doc->getCatalog()->getBaseURI()); obj.free(); return links; } void Page::display(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, -1, -1, -1, -1, printing, abortCheckCbk, abortCheckCbkData); } void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { #ifndef PDF_PARSER_ONLY PDFRectangle *mediaBox, *cropBox; PDFRectangle box; Gfx *gfx; Object obj; Annots *annotList; Dict *acroForm; int i; if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData)) { return; } rotate += getRotate(); if (rotate >= 360) { rotate -= 360; } else if (rotate < 0) { rotate += 360; } makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(), sliceX, sliceY, sliceW, sliceH, &box, &crop); cropBox = getCropBox(); if (globalParams->getPrintCommands()) { mediaBox = getMediaBox(); printf("***** MediaBox = ll:%g,%g ur:%g,%g\n", mediaBox->x1, mediaBox->y1, mediaBox->x2, mediaBox->y2); printf("***** CropBox = ll:%g,%g ur:%g,%g\n", cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); printf("***** Rotate = %d\n", attrs->getRotate()); } gfx = new Gfx(doc, out, num, attrs->getResourceDict(), hDPI, vDPI, &box, crop ? cropBox : (PDFRectangle *)NULL, rotate, abortCheckCbk, abortCheckCbkData); contents.fetch(xref, &obj); if (!obj.isNull()) { gfx->saveState(); gfx->display(&obj); gfx->restoreState(); } else { // empty pages need to call dump to do any setup required by the // OutputDev out->dump(); } obj.free(); // draw annotations if (globalParams->getDrawAnnotations()) { annotList = new Annots(doc, getAnnots(&obj)); obj.free(); acroForm = doc->getCatalog()->getAcroForm()->isDict() ? doc->getCatalog()->getAcroForm()->getDict() : NULL; if (acroForm) { if (acroForm->lookup("NeedAppearances", &obj)) { if (obj.isBool() && obj.getBool()) { annotList->generateAppearances(); } } obj.free(); } if (annotList->getNumAnnots() > 0) { if (globalParams->getPrintCommands()) { printf("***** Annotations\n"); } for (i = 0; i < annotList->getNumAnnots(); ++i) { annotList->getAnnot(i)->draw(gfx, printing); } out->dump(); } delete annotList; } delete gfx; #endif } void Page::makeBox(double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool upsideDown, double sliceX, double sliceY, double sliceW, double sliceH, PDFRectangle *box, GBool *crop) { PDFRectangle *mediaBox, *cropBox, *baseBox; double kx, ky; mediaBox = getMediaBox(); cropBox = getCropBox(); if (sliceW >= 0 && sliceH >= 0) { baseBox = useMediaBox ? mediaBox : cropBox; kx = 72.0 / hDPI; ky = 72.0 / vDPI; if (rotate == 90) { if (upsideDown) { box->x1 = baseBox->x1 + ky * sliceY; box->x2 = baseBox->x1 + ky * (sliceY + sliceH); } else { box->x1 = baseBox->x2 - ky * (sliceY + sliceH); box->x2 = baseBox->x2 - ky * sliceY; } box->y1 = baseBox->y1 + kx * sliceX; box->y2 = baseBox->y1 + kx * (sliceX + sliceW); } else if (rotate == 180) { box->x1 = baseBox->x2 - kx * (sliceX + sliceW); box->x2 = baseBox->x2 - kx * sliceX; if (upsideDown) { box->y1 = baseBox->y1 + ky * sliceY; box->y2 = baseBox->y1 + ky * (sliceY + sliceH); } else { box->y1 = baseBox->y2 - ky * (sliceY + sliceH); box->y2 = baseBox->y2 - ky * sliceY; } } else if (rotate == 270) { if (upsideDown) { box->x1 = baseBox->x2 - ky * (sliceY + sliceH); box->x2 = baseBox->x2 - ky * sliceY; } else { box->x1 = baseBox->x1 + ky * sliceY; box->x2 = baseBox->x1 + ky * (sliceY + sliceH); } box->y1 = baseBox->y2 - kx * (sliceX + sliceW); box->y2 = baseBox->y2 - kx * sliceX; } else { box->x1 = baseBox->x1 + kx * sliceX; box->x2 = baseBox->x1 + kx * (sliceX + sliceW); if (upsideDown) { box->y1 = baseBox->y2 - ky * (sliceY + sliceH); box->y2 = baseBox->y2 - ky * sliceY; } else { box->y1 = baseBox->y1 + ky * sliceY; box->y2 = baseBox->y1 + ky * (sliceY + sliceH); } } } else if (useMediaBox) { *box = *mediaBox; } else { *box = *cropBox; *crop = gFalse; } } void Page::processLinks(OutputDev *out) { Links *links; int i; links = getLinks(); for (i = 0; i < links->getNumLinks(); ++i) { out->processLink(links->getLink(i)); } delete links; } void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool upsideDown) { GfxState *state; int i; rotate += getRotate(); if (rotate >= 360) { rotate -= 360; } else if (rotate < 0) { rotate += 360; } state = new GfxState(hDPI, vDPI, useMediaBox ? getMediaBox() : getCropBox(), rotate, upsideDown); for (i = 0; i < 6; ++i) { ctm[i] = state->getCTM()[i]; } delete state; } xpdf-3.03/xpdf/Object.h0000644000076400007640000002056411622305345014242 0ustar dereknderekn//======================================================================== // // Object.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef OBJECT_H #define OBJECT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include #include "gtypes.h" #include "gmem.h" #include "GString.h" class XRef; class Array; class Dict; class Stream; //------------------------------------------------------------------------ // Ref //------------------------------------------------------------------------ struct Ref { int num; // object number int gen; // generation number }; //------------------------------------------------------------------------ // object types //------------------------------------------------------------------------ enum ObjType { // simple objects objBool, // boolean objInt, // integer objReal, // real objString, // string objName, // name objNull, // null // complex objects objArray, // array objDict, // dictionary objStream, // stream objRef, // indirect reference // special objects objCmd, // command name objError, // error return from Lexer objEOF, // end of file return from Lexer objNone // uninitialized object }; #define numObjTypes 14 // total number of object types //------------------------------------------------------------------------ // Object //------------------------------------------------------------------------ #ifdef DEBUG_MEM #define initObj(t) ++numAlloc[type = t] #else #define initObj(t) type = t #endif class Object { public: // Default constructor. Object(): type(objNone) {} // Initialize an object. Object *initBool(GBool boolnA) { initObj(objBool); booln = boolnA; return this; } Object *initInt(int intgA) { initObj(objInt); intg = intgA; return this; } Object *initReal(double realA) { initObj(objReal); real = realA; return this; } Object *initString(GString *stringA) { initObj(objString); string = stringA; return this; } Object *initName(const char *nameA) { initObj(objName); name = copyString(nameA); return this; } Object *initNull() { initObj(objNull); return this; } Object *initArray(XRef *xref); Object *initDict(XRef *xref); Object *initDict(Dict *dictA); Object *initStream(Stream *streamA); Object *initRef(int numA, int genA) { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } Object *initCmd(char *cmdA) { initObj(objCmd); cmd = copyString(cmdA); return this; } Object *initError() { initObj(objError); return this; } Object *initEOF() { initObj(objEOF); return this; } // Copy an object. Object *copy(Object *obj); // If object is a Ref, fetch and return the referenced object. // Otherwise, return a copy of the object. Object *fetch(XRef *xref, Object *obj, int recursion = 0); // Free object contents. void free(); // Type checking. ObjType getType() { return type; } GBool isBool() { return type == objBool; } GBool isInt() { return type == objInt; } GBool isReal() { return type == objReal; } GBool isNum() { return type == objInt || type == objReal; } GBool isString() { return type == objString; } GBool isName() { return type == objName; } GBool isNull() { return type == objNull; } GBool isArray() { return type == objArray; } GBool isDict() { return type == objDict; } GBool isStream() { return type == objStream; } GBool isRef() { return type == objRef; } GBool isCmd() { return type == objCmd; } GBool isError() { return type == objError; } GBool isEOF() { return type == objEOF; } GBool isNone() { return type == objNone; } // Special type checking. GBool isName(const char *nameA) { return type == objName && !strcmp(name, nameA); } GBool isDict(const char *dictType); GBool isStream(char *dictType); GBool isCmd(const char *cmdA) { return type == objCmd && !strcmp(cmd, cmdA); } // Accessors. NB: these assume object is of correct type. GBool getBool() { return booln; } int getInt() { return intg; } double getReal() { return real; } double getNum() { return type == objInt ? (double)intg : real; } GString *getString() { return string; } char *getName() { return name; } Array *getArray() { return array; } Dict *getDict() { return dict; } Stream *getStream() { return stream; } Ref getRef() { return ref; } int getRefNum() { return ref.num; } int getRefGen() { return ref.gen; } char *getCmd() { return cmd; } // Array accessors. int arrayGetLength(); void arrayAdd(Object *elem); Object *arrayGet(int i, Object *obj); Object *arrayGetNF(int i, Object *obj); // Dict accessors. int dictGetLength(); void dictAdd(char *key, Object *val); GBool dictIs(const char *dictType); Object *dictLookup(const char *key, Object *obj, int recursion = 0); Object *dictLookupNF(const char *key, Object *obj); char *dictGetKey(int i); Object *dictGetVal(int i, Object *obj); Object *dictGetValNF(int i, Object *obj); // Stream accessors. GBool streamIs(char *dictType); void streamReset(); void streamClose(); int streamGetChar(); int streamLookChar(); char *streamGetLine(char *buf, int size); Guint streamGetPos(); void streamSetPos(Guint pos, int dir = 0); Dict *streamGetDict(); // Output. const char *getTypeName(); void print(FILE *f = stdout); // Memory testing. static void memCheck(FILE *f); private: ObjType type; // object type union { // value for each type: GBool booln; // boolean int intg; // integer double real; // real GString *string; // string char *name; // name Array *array; // array Dict *dict; // dictionary Stream *stream; // stream Ref ref; // indirect reference char *cmd; // command }; #ifdef DEBUG_MEM static int // number of each type of object numAlloc[numObjTypes]; // currently allocated #endif }; //------------------------------------------------------------------------ // Array accessors. //------------------------------------------------------------------------ #include "Array.h" inline int Object::arrayGetLength() { return array->getLength(); } inline void Object::arrayAdd(Object *elem) { array->add(elem); } inline Object *Object::arrayGet(int i, Object *obj) { return array->get(i, obj); } inline Object *Object::arrayGetNF(int i, Object *obj) { return array->getNF(i, obj); } //------------------------------------------------------------------------ // Dict accessors. //------------------------------------------------------------------------ #include "Dict.h" inline int Object::dictGetLength() { return dict->getLength(); } inline void Object::dictAdd(char *key, Object *val) { dict->add(key, val); } inline GBool Object::dictIs(const char *dictType) { return dict->is(dictType); } inline GBool Object::isDict(const char *dictType) { return type == objDict && dictIs(dictType); } inline Object *Object::dictLookup(const char *key, Object *obj, int recursion) { return dict->lookup(key, obj, recursion); } inline Object *Object::dictLookupNF(const char *key, Object *obj) { return dict->lookupNF(key, obj); } inline char *Object::dictGetKey(int i) { return dict->getKey(i); } inline Object *Object::dictGetVal(int i, Object *obj) { return dict->getVal(i, obj); } inline Object *Object::dictGetValNF(int i, Object *obj) { return dict->getValNF(i, obj); } //------------------------------------------------------------------------ // Stream accessors. //------------------------------------------------------------------------ #include "Stream.h" inline GBool Object::streamIs(char *dictType) { return stream->getDict()->is(dictType); } inline GBool Object::isStream(char *dictType) { return type == objStream && streamIs(dictType); } inline void Object::streamReset() { stream->reset(); } inline void Object::streamClose() { stream->close(); } inline int Object::streamGetChar() { return stream->getChar(); } inline int Object::streamLookChar() { return stream->lookChar(); } inline char *Object::streamGetLine(char *buf, int size) { return stream->getLine(buf, size); } inline Guint Object::streamGetPos() { return stream->getPos(); } inline void Object::streamSetPos(Guint pos, int dir) { stream->setPos(pos, dir); } inline Dict *Object::streamGetDict() { return stream->getDict(); } #endif xpdf-3.03/xpdf/XpdfPluginAPI.cc0000644000076400007640000001316011622305345015576 0ustar dereknderekn//======================================================================== // // XpdfPluginAPI.cc // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include "aconf.h" #ifdef ENABLE_PLUGINS #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "PDFDoc.h" #ifdef WIN32 #include "WinPDFCore.h" #else #include "XPDFCore.h" #endif #include "XpdfPluginAPI.h" //------------------------------------------------------------------------ //~ This should use a pool of Objects; change xpdfFreeObj to match. static Object *allocObj() { return (Object *)gmalloc(sizeof(Object)); } //------------------------------------------------------------------------ // Document access functions //------------------------------------------------------------------------ XpdfObject _xpdfGetInfoDict(XpdfDoc doc) { Object *obj; obj = allocObj(); return (XpdfObject)((PDFDoc *)doc)->getDocInfo(obj); } XpdfObject _xpdfGetCatalog(XpdfDoc doc) { Object *obj; obj = allocObj(); return (XpdfObject)((PDFDoc *)doc)->getXRef()->getCatalog(obj); } #ifdef _WIN32 HWND _xpdfWin32GetWindow(XpdfDoc doc) { WinPDFCore *core; if (!(core = (WinPDFCore *)((PDFDoc *)doc)->getCore())) { return NULL; } return core->getDrawFrame(); } #else Widget _xpdfXGetWindow(XpdfDoc doc) { XPDFCore *core; if (!(core = (XPDFCore *)((PDFDoc *)doc)->getCore())) { return NULL; } return core->getWidget(); } #endif //------------------------------------------------------------------------ // Object access functions. //------------------------------------------------------------------------ XpdfBool _xpdfObjIsBool(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isBool(); } XpdfBool _xpdfObjIsInt(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isInt(); } XpdfBool _xpdfObjIsReal(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isReal(); } XpdfBool _xpdfObjIsNumber(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isNum(); } XpdfBool _xpdfObjIsString(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isString(); } XpdfBool _xpdfObjIsName(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isName(); } XpdfBool _xpdfObjIsNull(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isNull(); } XpdfBool _xpdfObjIsArray(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isArray(); } XpdfBool _xpdfObjIsDict(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isDict(); } XpdfBool _xpdfObjIsStream(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isStream(); } XpdfBool _xpdfObjIsRef(XpdfObject obj) { return (XpdfBool)((Object *)obj)->isRef(); } XpdfBool _xpdfBoolValue(XpdfObject obj) { return (XpdfBool)((Object *)obj)->getBool(); } int _xpdfIntValue(XpdfObject obj) { if (!((Object *)obj)->isInt()) { return 0; } return ((Object *)obj)->getInt(); } double _xpdfRealValue(XpdfObject obj) { if (!((Object *)obj)->isReal()) { return 0; } return ((Object *)obj)->getReal(); } double _xpdfNumberValue(XpdfObject obj) { if (!((Object *)obj)->isNum()) { return 0; } return ((Object *)obj)->getNum(); } int _xpdfStringLength(XpdfObject obj) { if (!((Object *)obj)->isString()) { return 0; } return ((Object *)obj)->getString()->getLength(); } char *_xpdfStringValue(XpdfObject obj) { if (!((Object *)obj)->isString()) { return 0; } return ((Object *)obj)->getString()->getCString(); } char *_xpdfNameValue(XpdfObject obj) { if (!((Object *)obj)->isName()) { return NULL; } return ((Object *)obj)->getName(); } int _xpdfArrayLength(XpdfObject obj) { if (!((Object *)obj)->isArray()) { return 0; } return ((Object *)obj)->arrayGetLength(); } XpdfObject _xpdfArrayGet(XpdfObject obj, int idx) { Object *elem; elem = allocObj(); if (!((Object *)obj)->isArray()) { return (XpdfObject)elem->initNull(); } return (XpdfObject)((Object *)obj)->arrayGet(idx, elem); } XpdfObject _xpdfDictGet(XpdfObject obj, char *key) { Object *elem; elem = allocObj(); if (!((Object *)obj)->isDict()) { return (XpdfObject)elem->initNull(); } return (XpdfObject)((Object *)obj)->dictLookup(key, elem); } void _xpdfFreeObj(XpdfObject obj) { ((Object *)obj)->free(); gfree(obj); } //------------------------------------------------------------------------ // Memory allocation functions //------------------------------------------------------------------------ void *_xpdfMalloc(int size) { return gmalloc(size); } void *_xpdfRealloc(void *p, int size) { return grealloc(p, size); } void _xpdfFree(void *p) { gfree(p); } //------------------------------------------------------------------------ // Security handlers //------------------------------------------------------------------------ void _xpdfRegisterSecurityHandler(XpdfSecurityHandler *handler) { if (handler->version <= xpdfPluginAPIVersion) { globalParams->addSecurityHandler(handler); } } //------------------------------------------------------------------------ XpdfPluginVecTable xpdfPluginVecTable = { xpdfPluginAPIVersion, &_xpdfGetInfoDict, &_xpdfGetCatalog, #ifdef _WIN32 &_xpdfWin32GetWindow, #else &_xpdfXGetWindow, #endif &_xpdfObjIsBool, &_xpdfObjIsInt, &_xpdfObjIsReal, &_xpdfObjIsString, &_xpdfObjIsName, &_xpdfObjIsNull, &_xpdfObjIsArray, &_xpdfObjIsDict, &_xpdfObjIsStream, &_xpdfObjIsRef, &_xpdfBoolValue, &_xpdfIntValue, &_xpdfRealValue, &_xpdfStringLength, &_xpdfStringValue, &_xpdfNameValue, &_xpdfArrayLength, &_xpdfArrayGet, &_xpdfDictGet, &_xpdfFreeObj, &_xpdfMalloc, &_xpdfRealloc, &_xpdfFree, &_xpdfRegisterSecurityHandler, }; #endif // ENABLE_PLUGINS xpdf-3.03/xpdf/SecurityHandler.h0000644000076400007640000001202111622305345016126 0ustar dereknderekn//======================================================================== // // SecurityHandler.h // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #ifndef SECURITYHANDLER_H #define SECURITYHANDLER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" class GString; class PDFDoc; struct XpdfSecurityHandler; //------------------------------------------------------------------------ // SecurityHandler //------------------------------------------------------------------------ class SecurityHandler { public: static SecurityHandler *make(PDFDoc *docA, Object *encryptDictA); SecurityHandler(PDFDoc *docA); virtual ~SecurityHandler(); // Returns true if the file is actually unencrypted. virtual GBool isUnencrypted() { return gFalse; } // Check the document's encryption. If the document is encrypted, // this will first try and (in // "batch" mode), and if those fail, it will attempt to request a // password from the user. This is the high-level function that // calls the lower level functions for the specific security handler // (requesting a password three times, etc.). Returns true if the // document can be opened (if it's unencrypted, or if a correct // password is obtained); false otherwise (encrypted and no correct // password). GBool checkEncryption(GString *ownerPassword, GString *userPassword); // Create authorization data for the specified owner and user // passwords. If the security handler doesn't support "batch" mode, // this function should return NULL. virtual void *makeAuthData(GString *ownerPassword, GString *userPassword) = 0; // Construct authorization data, typically by prompting the user for // a password. Returns an authorization data object, or NULL to // cancel. virtual void *getAuthData() = 0; // Free the authorization data returned by makeAuthData or // getAuthData. virtual void freeAuthData(void *authData) = 0; // Attempt to authorize the document, using the supplied // authorization data (which may be NULL). Returns true if // successful (i.e., if at least the right to open the document was // granted). virtual GBool authorize(void *authData) = 0; // Return the various authorization parameters. These are only // valid after authorize has returned true. virtual int getPermissionFlags() = 0; virtual GBool getOwnerPasswordOk() = 0; virtual Guchar *getFileKey() = 0; virtual int getFileKeyLength() = 0; virtual int getEncVersion() = 0; virtual CryptAlgorithm getEncAlgorithm() = 0; protected: PDFDoc *doc; }; //------------------------------------------------------------------------ // StandardSecurityHandler //------------------------------------------------------------------------ class StandardSecurityHandler: public SecurityHandler { public: StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA); virtual ~StandardSecurityHandler(); virtual GBool isUnencrypted(); virtual void *makeAuthData(GString *ownerPassword, GString *userPassword); virtual void *getAuthData(); virtual void freeAuthData(void *authData); virtual GBool authorize(void *authData); virtual int getPermissionFlags() { return permFlags; } virtual GBool getOwnerPasswordOk() { return ownerPasswordOk; } virtual Guchar *getFileKey() { return fileKey; } virtual int getFileKeyLength() { return fileKeyLength; } virtual int getEncVersion() { return encVersion; } virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } private: int permFlags; GBool ownerPasswordOk; Guchar fileKey[32]; int fileKeyLength; int encVersion; int encRevision; CryptAlgorithm encAlgorithm; GBool encryptMetadata; GString *ownerKey, *userKey; GString *ownerEnc, *userEnc; GString *fileID; GBool ok; }; #ifdef ENABLE_PLUGINS //------------------------------------------------------------------------ // ExternalSecurityHandler //------------------------------------------------------------------------ class ExternalSecurityHandler: public SecurityHandler { public: ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, XpdfSecurityHandler *xshA); virtual ~ExternalSecurityHandler(); virtual void *makeAuthData(GString *ownerPassword, GString *userPassword); virtual void *getAuthData(); virtual void freeAuthData(void *authData); virtual GBool authorize(void *authData); virtual int getPermissionFlags() { return permFlags; } virtual GBool getOwnerPasswordOk() { return gFalse; } virtual Guchar *getFileKey() { return fileKey; } virtual int getFileKeyLength() { return fileKeyLength; } virtual int getEncVersion() { return encVersion; } virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } private: Object encryptDict; XpdfSecurityHandler *xsh; void *docData; int permFlags; Guchar fileKey[16]; int fileKeyLength; int encVersion; CryptAlgorithm encAlgorithm; GBool ok; }; #endif // ENABLE_PLUGINS #endif xpdf-3.03/xpdf/Stream-CCITT.h0000644000076400007640000004207711622305345015136 0ustar dereknderekn//======================================================================== // // Stream-CCITT.h // // Tables for CCITT Fax decoding. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef STREAM_CCITT_H #define STREAM_CCITT_H struct CCITTCode { short bits; short n; }; #define ccittEOL -2 //------------------------------------------------------------------------ // 2D codes //------------------------------------------------------------------------ #define twoDimPass 0 #define twoDimHoriz 1 #define twoDimVert0 2 #define twoDimVertR1 3 #define twoDimVertL1 4 #define twoDimVertR2 5 #define twoDimVertL2 6 #define twoDimVertR3 7 #define twoDimVertL3 8 // 1-7 bit codes static CCITTCode twoDimTab1[128] = { {-1, -1}, {-1, -1}, // 000000x {7, twoDimVertL3}, // 0000010 {7, twoDimVertR3}, // 0000011 {6, twoDimVertL2}, {6, twoDimVertL2}, // 000010x {6, twoDimVertR2}, {6, twoDimVertR2}, // 000011x {4, twoDimPass}, {4, twoDimPass}, // 0001xxx {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {4, twoDimPass}, {3, twoDimHoriz}, {3, twoDimHoriz}, // 001xxxx {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimHoriz}, {3, twoDimVertL1}, {3, twoDimVertL1}, // 010xxxx {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertL1}, {3, twoDimVertR1}, {3, twoDimVertR1}, // 011xxxx {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {3, twoDimVertR1}, {1, twoDimVert0}, {1, twoDimVert0}, // 1xxxxxx {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0}, {1, twoDimVert0} }; //------------------------------------------------------------------------ // white run lengths //------------------------------------------------------------------------ // 11-12 bit codes (upper 7 bits are 0) static CCITTCode whiteTab1[32] = { {-1, -1}, // 00000 {12, ccittEOL}, // 00001 {-1, -1}, {-1, -1}, // 0001x {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 001xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 010xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 011xx {11, 1792}, {11, 1792}, // 1000x {12, 1984}, // 10010 {12, 2048}, // 10011 {12, 2112}, // 10100 {12, 2176}, // 10101 {12, 2240}, // 10110 {12, 2304}, // 10111 {11, 1856}, {11, 1856}, // 1100x {11, 1920}, {11, 1920}, // 1101x {12, 2368}, // 11100 {12, 2432}, // 11101 {12, 2496}, // 11110 {12, 2560} // 11111 }; // 1-9 bit codes static CCITTCode whiteTab2[512] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000000xx {8, 29}, {8, 29}, // 00000010x {8, 30}, {8, 30}, // 00000011x {8, 45}, {8, 45}, // 00000100x {8, 46}, {8, 46}, // 00000101x {7, 22}, {7, 22}, {7, 22}, {7, 22}, // 0000011xx {7, 23}, {7, 23}, {7, 23}, {7, 23}, // 0000100xx {8, 47}, {8, 47}, // 00001010x {8, 48}, {8, 48}, // 00001011x {6, 13}, {6, 13}, {6, 13}, {6, 13}, // 000011xxx {6, 13}, {6, 13}, {6, 13}, {6, 13}, {7, 20}, {7, 20}, {7, 20}, {7, 20}, // 0001000xx {8, 33}, {8, 33}, // 00010010x {8, 34}, {8, 34}, // 00010011x {8, 35}, {8, 35}, // 00010100x {8, 36}, {8, 36}, // 00010101x {8, 37}, {8, 37}, // 00010110x {8, 38}, {8, 38}, // 00010111x {7, 19}, {7, 19}, {7, 19}, {7, 19}, // 0001100xx {8, 31}, {8, 31}, // 00011010x {8, 32}, {8, 32}, // 00011011x {6, 1}, {6, 1}, {6, 1}, {6, 1}, // 000111xxx {6, 1}, {6, 1}, {6, 1}, {6, 1}, {6, 12}, {6, 12}, {6, 12}, {6, 12}, // 001000xxx {6, 12}, {6, 12}, {6, 12}, {6, 12}, {8, 53}, {8, 53}, // 00100100x {8, 54}, {8, 54}, // 00100101x {7, 26}, {7, 26}, {7, 26}, {7, 26}, // 0010011xx {8, 39}, {8, 39}, // 00101000x {8, 40}, {8, 40}, // 00101001x {8, 41}, {8, 41}, // 00101010x {8, 42}, {8, 42}, // 00101011x {8, 43}, {8, 43}, // 00101100x {8, 44}, {8, 44}, // 00101101x {7, 21}, {7, 21}, {7, 21}, {7, 21}, // 0010111xx {7, 28}, {7, 28}, {7, 28}, {7, 28}, // 0011000xx {8, 61}, {8, 61}, // 00110010x {8, 62}, {8, 62}, // 00110011x {8, 63}, {8, 63}, // 00110100x {8, 0}, {8, 0}, // 00110101x {8, 320}, {8, 320}, // 00110110x {8, 384}, {8, 384}, // 00110111x {5, 10}, {5, 10}, {5, 10}, {5, 10}, // 00111xxxx {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 10}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, // 01000xxxx {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {5, 11}, {7, 27}, {7, 27}, {7, 27}, {7, 27}, // 0100100xx {8, 59}, {8, 59}, // 01001010x {8, 60}, {8, 60}, // 01001011x {9, 1472}, // 010011000 {9, 1536}, // 010011001 {9, 1600}, // 010011010 {9, 1728}, // 010011011 {7, 18}, {7, 18}, {7, 18}, {7, 18}, // 0100111xx {7, 24}, {7, 24}, {7, 24}, {7, 24}, // 0101000xx {8, 49}, {8, 49}, // 01010010x {8, 50}, {8, 50}, // 01010011x {8, 51}, {8, 51}, // 01010100x {8, 52}, {8, 52}, // 01010101x {7, 25}, {7, 25}, {7, 25}, {7, 25}, // 0101011xx {8, 55}, {8, 55}, // 01011000x {8, 56}, {8, 56}, // 01011001x {8, 57}, {8, 57}, // 01011010x {8, 58}, {8, 58}, // 01011011x {6, 192}, {6, 192}, {6, 192}, {6, 192}, // 010111xxx {6, 192}, {6, 192}, {6, 192}, {6, 192}, {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, // 011000xxx {6, 1664}, {6, 1664}, {6, 1664}, {6, 1664}, {8, 448}, {8, 448}, // 01100100x {8, 512}, {8, 512}, // 01100101x {9, 704}, // 011001100 {9, 768}, // 011001101 {8, 640}, {8, 640}, // 01100111x {8, 576}, {8, 576}, // 01101000x {9, 832}, // 011010010 {9, 896}, // 011010011 {9, 960}, // 011010100 {9, 1024}, // 011010101 {9, 1088}, // 011010110 {9, 1152}, // 011010111 {9, 1216}, // 011011000 {9, 1280}, // 011011001 {9, 1344}, // 011011010 {9, 1408}, // 011011011 {7, 256}, {7, 256}, {7, 256}, {7, 256}, // 0110111xx {4, 2}, {4, 2}, {4, 2}, {4, 2}, // 0111xxxxx {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 2}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, // 1000xxxxx {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {4, 3}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, // 10010xxxx {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 128}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, // 10011xxxx {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 8}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, // 10100xxxx {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {5, 9}, {6, 16}, {6, 16}, {6, 16}, {6, 16}, // 101010xxx {6, 16}, {6, 16}, {6, 16}, {6, 16}, {6, 17}, {6, 17}, {6, 17}, {6, 17}, // 101011xxx {6, 17}, {6, 17}, {6, 17}, {6, 17}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, // 1011xxxxx {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 4}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 1100xxxxx {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {4, 5}, {6, 14}, {6, 14}, {6, 14}, {6, 14}, // 110100xxx {6, 14}, {6, 14}, {6, 14}, {6, 14}, {6, 15}, {6, 15}, {6, 15}, {6, 15}, // 110101xxx {6, 15}, {6, 15}, {6, 15}, {6, 15}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, // 11011xxxx {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {5, 64}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 1110xxxxx {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 6}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, // 1111xxxxx {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7}, {4, 7} }; //------------------------------------------------------------------------ // black run lengths //------------------------------------------------------------------------ // 10-13 bit codes (upper 6 bits are 0) static CCITTCode blackTab1[128] = { {-1, -1}, {-1, -1}, // 000000000000x {12, ccittEOL}, {12, ccittEOL}, // 000000000001x {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000001xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000010xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000011xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000100xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000101xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000110xx {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 00000000111xx {11, 1792}, {11, 1792}, {11, 1792}, {11, 1792}, // 00000001000xx {12, 1984}, {12, 1984}, // 000000010010x {12, 2048}, {12, 2048}, // 000000010011x {12, 2112}, {12, 2112}, // 000000010100x {12, 2176}, {12, 2176}, // 000000010101x {12, 2240}, {12, 2240}, // 000000010110x {12, 2304}, {12, 2304}, // 000000010111x {11, 1856}, {11, 1856}, {11, 1856}, {11, 1856}, // 00000001100xx {11, 1920}, {11, 1920}, {11, 1920}, {11, 1920}, // 00000001101xx {12, 2368}, {12, 2368}, // 000000011100x {12, 2432}, {12, 2432}, // 000000011101x {12, 2496}, {12, 2496}, // 000000011110x {12, 2560}, {12, 2560}, // 000000011111x {10, 18}, {10, 18}, {10, 18}, {10, 18}, // 0000001000xxx {10, 18}, {10, 18}, {10, 18}, {10, 18}, {12, 52}, {12, 52}, // 000000100100x {13, 640}, // 0000001001010 {13, 704}, // 0000001001011 {13, 768}, // 0000001001100 {13, 832}, // 0000001001101 {12, 55}, {12, 55}, // 000000100111x {12, 56}, {12, 56}, // 000000101000x {13, 1280}, // 0000001010010 {13, 1344}, // 0000001010011 {13, 1408}, // 0000001010100 {13, 1472}, // 0000001010101 {12, 59}, {12, 59}, // 000000101011x {12, 60}, {12, 60}, // 000000101100x {13, 1536}, // 0000001011010 {13, 1600}, // 0000001011011 {11, 24}, {11, 24}, {11, 24}, {11, 24}, // 00000010111xx {11, 25}, {11, 25}, {11, 25}, {11, 25}, // 00000011000xx {13, 1664}, // 0000001100100 {13, 1728}, // 0000001100101 {12, 320}, {12, 320}, // 000000110011x {12, 384}, {12, 384}, // 000000110100x {12, 448}, {12, 448}, // 000000110101x {13, 512}, // 0000001101100 {13, 576}, // 0000001101101 {12, 53}, {12, 53}, // 000000110111x {12, 54}, {12, 54}, // 000000111000x {13, 896}, // 0000001110010 {13, 960}, // 0000001110011 {13, 1024}, // 0000001110100 {13, 1088}, // 0000001110101 {13, 1152}, // 0000001110110 {13, 1216}, // 0000001110111 {10, 64}, {10, 64}, {10, 64}, {10, 64}, // 0000001111xxx {10, 64}, {10, 64}, {10, 64}, {10, 64} }; // 7-12 bit codes (upper 4 bits are 0) static CCITTCode blackTab2[192] = { {8, 13}, {8, 13}, {8, 13}, {8, 13}, // 00000100xxxx {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {8, 13}, {11, 23}, {11, 23}, // 00000101000x {12, 50}, // 000001010010 {12, 51}, // 000001010011 {12, 44}, // 000001010100 {12, 45}, // 000001010101 {12, 46}, // 000001010110 {12, 47}, // 000001010111 {12, 57}, // 000001011000 {12, 58}, // 000001011001 {12, 61}, // 000001011010 {12, 256}, // 000001011011 {10, 16}, {10, 16}, {10, 16}, {10, 16}, // 0000010111xx {10, 17}, {10, 17}, {10, 17}, {10, 17}, // 0000011000xx {12, 48}, // 000001100100 {12, 49}, // 000001100101 {12, 62}, // 000001100110 {12, 63}, // 000001100111 {12, 30}, // 000001101000 {12, 31}, // 000001101001 {12, 32}, // 000001101010 {12, 33}, // 000001101011 {12, 40}, // 000001101100 {12, 41}, // 000001101101 {11, 22}, {11, 22}, // 00000110111x {8, 14}, {8, 14}, {8, 14}, {8, 14}, // 00000111xxxx {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {8, 14}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, // 0000100xxxxx {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 10}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, // 0000101xxxxx {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {7, 11}, {9, 15}, {9, 15}, {9, 15}, {9, 15}, // 000011000xxx {9, 15}, {9, 15}, {9, 15}, {9, 15}, {12, 128}, // 000011001000 {12, 192}, // 000011001001 {12, 26}, // 000011001010 {12, 27}, // 000011001011 {12, 28}, // 000011001100 {12, 29}, // 000011001101 {11, 19}, {11, 19}, // 00001100111x {11, 20}, {11, 20}, // 00001101000x {12, 34}, // 000011010010 {12, 35}, // 000011010011 {12, 36}, // 000011010100 {12, 37}, // 000011010101 {12, 38}, // 000011010110 {12, 39}, // 000011010111 {11, 21}, {11, 21}, // 00001101100x {12, 42}, // 000011011010 {12, 43}, // 000011011011 {10, 0}, {10, 0}, {10, 0}, {10, 0}, // 0000110111xx {7, 12}, {7, 12}, {7, 12}, {7, 12}, // 0000111xxxxx {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12}, {7, 12} }; // 2-6 bit codes static CCITTCode blackTab3[64] = { {-1, -1}, {-1, -1}, {-1, -1}, {-1, -1}, // 0000xx {6, 9}, // 000100 {6, 8}, // 000101 {5, 7}, {5, 7}, // 00011x {4, 6}, {4, 6}, {4, 6}, {4, 6}, // 0010xx {4, 5}, {4, 5}, {4, 5}, {4, 5}, // 0011xx {3, 1}, {3, 1}, {3, 1}, {3, 1}, // 010xxx {3, 1}, {3, 1}, {3, 1}, {3, 1}, {3, 4}, {3, 4}, {3, 4}, {3, 4}, // 011xxx {3, 4}, {3, 4}, {3, 4}, {3, 4}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, // 10xxxx {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 3}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, // 11xxxx {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2}, {2, 2} }; #endif xpdf-3.03/xpdf/forwardArrowDis.xbm0000644000076400007640000000046111622305345016504 0ustar dereknderekn#define forwardArrowDis_width 16 #define forwardArrowDis_height 15 static unsigned char forwardArrowDis_bits[] = { 0x00, 0x01, 0x00, 0x02, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x15, 0x22, 0x2a, 0x11, 0x55, 0x22, 0xaa, 0x11, 0x55, 0x22, 0x2a, 0x00, 0x15, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x02, 0x00, 0x01}; xpdf-3.03/xpdf/Outline.h0000644000076400007640000000271411622305345014450 0ustar dereknderekn//======================================================================== // // Outline.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef OUTLINE_H #define OUTLINE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" #include "CharTypes.h" class GString; class GList; class XRef; class LinkAction; //------------------------------------------------------------------------ class Outline { public: Outline(Object *outlineObj, XRef *xref); ~Outline(); GList *getItems() { return items; } private: GList *items; // NULL if document has no outline // [OutlineItem] }; //------------------------------------------------------------------------ class OutlineItem { public: OutlineItem(Dict *dict, XRef *xrefA); ~OutlineItem(); static GList *readItemList(Object *firstItemRef, Object *lastItemRef, XRef *xrefA); void open(); void close(); Unicode *getTitle() { return title; } int getTitleLength() { return titleLen; } LinkAction *getAction() { return action; } GBool isOpen() { return startsOpen; } GBool hasKids() { return firstRef.isRef(); } GList *getKids() { return kids; } private: XRef *xref; Unicode *title; int titleLen; LinkAction *action; Object firstRef; Object lastRef; Object nextRef; GBool startsOpen; GList *kids; // NULL unless this item is open [OutlineItem] }; #endif xpdf-3.03/xpdf/SplashOutputDev.cc0000644000076400007640000025206711622305345016311 0ustar dereknderekn//======================================================================== // // SplashOutputDev.cc // // Copyright 2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gfile.h" #include "GlobalParams.h" #include "Error.h" #include "Object.h" #include "Gfx.h" #include "GfxFont.h" #include "Link.h" #include "CharCodeToUnicode.h" #include "FontEncodingTables.h" #include "BuiltinFont.h" #include "BuiltinFontTables.h" #include "FoFiTrueType.h" #include "SplashBitmap.h" #include "SplashGlyphBitmap.h" #include "SplashPattern.h" #include "SplashScreen.h" #include "SplashPath.h" #include "SplashState.h" #include "SplashErrorCodes.h" #include "SplashFontEngine.h" #include "SplashFont.h" #include "SplashFontFile.h" #include "SplashFontFileID.h" #include "Splash.h" #include "SplashOutputDev.h" #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #endif //------------------------------------------------------------------------ // Type 3 font cache size parameters #define type3FontCacheAssoc 8 #define type3FontCacheMaxSets 8 #define type3FontCacheSize (128*1024) //------------------------------------------------------------------------ // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } //------------------------------------------------------------------------ // Blend functions //------------------------------------------------------------------------ static void splashOutBlendMultiply(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = (dest[i] * src[i]) / 255; } } static void splashOutBlendScreen(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] + src[i] - (dest[i] * src[i]) / 255; } } static void splashOutBlendOverlay(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] < 0x80 ? (src[i] * 2 * dest[i]) / 255 : 255 - 2 * ((255 - src[i]) * (255 - dest[i])) / 255; } } static void splashOutBlendDarken(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] < src[i] ? dest[i] : src[i]; } } static void splashOutBlendLighten(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] > src[i] ? dest[i] : src[i]; } } static void splashOutBlendColorDodge(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i, x; for (i = 0; i < splashColorModeNComps[cm]; ++i) { if (src[i] == 255) { blend[i] = 255; } else { x = (dest[i] * 255) / (255 - src[i]); blend[i] = x <= 255 ? x : 255; } } } static void splashOutBlendColorBurn(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i, x; for (i = 0; i < splashColorModeNComps[cm]; ++i) { if (src[i] == 0) { blend[i] = 0; } else { x = ((255 - dest[i]) * 255) / src[i]; blend[i] = x <= 255 ? 255 - x : 0; } } } static void splashOutBlendHardLight(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = src[i] < 0x80 ? (dest[i] * 2 * src[i]) / 255 : 255 - 2 * ((255 - dest[i]) * (255 - src[i])) / 255; } } static void splashOutBlendSoftLight(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i, x; for (i = 0; i < splashColorModeNComps[cm]; ++i) { if (src[i] < 0x80) { blend[i] = dest[i] - (255 - 2 * src[i]) * dest[i] * (255 - dest[i]) / (255 * 255); } else { if (dest[i] < 0x40) { x = (((((16 * dest[i] - 12 * 255) * dest[i]) / 255) + 4 * 255) * dest[i]) / 255; } else { x = (int)sqrt(255.0 * dest[i]); } blend[i] = dest[i] + (2 * src[i] - 255) * (x - dest[i]) / 255; } } } static void splashOutBlendDifference(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] < src[i] ? src[i] - dest[i] : dest[i] - src[i]; } } static void splashOutBlendExclusion(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = dest[i] + src[i] - (2 * dest[i] * src[i]) / 255; } } static int getLum(int r, int g, int b) { return (int)(0.3 * r + 0.59 * g + 0.11 * b); } static int getSat(int r, int g, int b) { int rgbMin, rgbMax; rgbMin = rgbMax = r; if (g < rgbMin) { rgbMin = g; } else if (g > rgbMax) { rgbMax = g; } if (b < rgbMin) { rgbMin = b; } else if (b > rgbMax) { rgbMax = b; } return rgbMax - rgbMin; } static void clipColor(int rIn, int gIn, int bIn, Guchar *rOut, Guchar *gOut, Guchar *bOut) { int lum, rgbMin, rgbMax; lum = getLum(rIn, gIn, bIn); rgbMin = rgbMax = rIn; if (gIn < rgbMin) { rgbMin = gIn; } else if (gIn > rgbMax) { rgbMax = gIn; } if (bIn < rgbMin) { rgbMin = bIn; } else if (bIn > rgbMax) { rgbMax = bIn; } if (rgbMin < 0) { *rOut = (Guchar)(lum + ((rIn - lum) * lum) / (lum - rgbMin)); *gOut = (Guchar)(lum + ((gIn - lum) * lum) / (lum - rgbMin)); *bOut = (Guchar)(lum + ((bIn - lum) * lum) / (lum - rgbMin)); } else if (rgbMax > 255) { *rOut = (Guchar)(lum + ((rIn - lum) * (255 - lum)) / (rgbMax - lum)); *gOut = (Guchar)(lum + ((gIn - lum) * (255 - lum)) / (rgbMax - lum)); *bOut = (Guchar)(lum + ((bIn - lum) * (255 - lum)) / (rgbMax - lum)); } else { *rOut = rIn; *gOut = gIn; *bOut = bIn; } } static void setLum(Guchar rIn, Guchar gIn, Guchar bIn, int lum, Guchar *rOut, Guchar *gOut, Guchar *bOut) { int d; d = lum - getLum(rIn, gIn, bIn); clipColor(rIn + d, gIn + d, bIn + d, rOut, gOut, bOut); } static void setSat(Guchar rIn, Guchar gIn, Guchar bIn, int sat, Guchar *rOut, Guchar *gOut, Guchar *bOut) { int rgbMin, rgbMid, rgbMax; Guchar *minOut, *midOut, *maxOut; if (rIn < gIn) { rgbMin = rIn; minOut = rOut; rgbMid = gIn; midOut = gOut; } else { rgbMin = gIn; minOut = gOut; rgbMid = rIn; midOut = rOut; } if (bIn > rgbMid) { rgbMax = bIn; maxOut = bOut; } else if (bIn > rgbMin) { rgbMax = rgbMid; maxOut = midOut; rgbMid = bIn; midOut = bOut; } else { rgbMax = rgbMid; maxOut = midOut; rgbMid = rgbMin; midOut = minOut; rgbMin = bIn; minOut = bOut; } if (rgbMax > rgbMin) { *midOut = (Guchar)((rgbMid - rgbMin) * sat) / (rgbMax - rgbMin); *maxOut = (Guchar)sat; } else { *midOut = *maxOut = 0; } *minOut = 0; } static void splashOutBlendHue(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { Guchar r0, g0, b0, r1, g1, b1; switch (cm) { case splashModeMono1: case splashModeMono8: blend[0] = dest[0]; break; case splashModeRGB8: case splashModeBGR8: setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]), &r0, &g0, &b0); setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), &blend[0], &blend[1], &blend[2]); break; #if SPLASH_CMYK case splashModeCMYK8: // NB: inputs have already been converted to additive mode setSat(src[0], src[1], src[2], getSat(dest[0], dest[1], dest[2]), &r0, &g0, &b0); setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), &r1, &g1, &b1); blend[0] = r1; blend[1] = g1; blend[2] = b1; blend[3] = dest[3]; break; #endif } } static void splashOutBlendSaturation(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { Guchar r0, g0, b0, r1, g1, b1; switch (cm) { case splashModeMono1: case splashModeMono8: blend[0] = dest[0]; break; case splashModeRGB8: case splashModeBGR8: setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]), &r0, &g0, &b0); setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), &blend[0], &blend[1], &blend[2]); break; #if SPLASH_CMYK case splashModeCMYK8: // NB: inputs have already been converted to additive mode setSat(dest[0], dest[1], dest[2], getSat(src[0], src[1], src[2]), &r0, &g0, &b0); setLum(r0, g0, b0, getLum(dest[0], dest[1], dest[2]), &r1, &g1, &b1); blend[0] = r1; blend[1] = g1; blend[2] = b1; blend[3] = dest[3]; break; #endif } } static void splashOutBlendColor(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { #if SPLASH_CMYK Guchar r, g, b; #endif switch (cm) { case splashModeMono1: case splashModeMono8: blend[0] = dest[0]; break; case splashModeRGB8: case splashModeBGR8: setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]), &blend[0], &blend[1], &blend[2]); break; #if SPLASH_CMYK case splashModeCMYK8: // NB: inputs have already been converted to additive mode setLum(src[0], src[1], src[2], getLum(dest[0], dest[1], dest[2]), &r, &g, &b); blend[0] = r; blend[1] = g; blend[2] = b; blend[3] = dest[3]; break; #endif } } static void splashOutBlendLuminosity(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { #if SPLASH_CMYK Guchar r, g, b; #endif switch (cm) { case splashModeMono1: case splashModeMono8: blend[0] = dest[0]; break; case splashModeRGB8: case splashModeBGR8: setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]), &blend[0], &blend[1], &blend[2]); break; #if SPLASH_CMYK case splashModeCMYK8: // NB: inputs have already been converted to additive mode setLum(dest[0], dest[1], dest[2], getLum(src[0], src[1], src[2]), &r, &g, &b); blend[0] = r; blend[1] = g; blend[2] = b; blend[3] = src[3]; break; #endif } } // NB: This must match the GfxBlendMode enum defined in GfxState.h. SplashBlendFunc splashOutBlendFuncs[] = { NULL, &splashOutBlendMultiply, &splashOutBlendScreen, &splashOutBlendOverlay, &splashOutBlendDarken, &splashOutBlendLighten, &splashOutBlendColorDodge, &splashOutBlendColorBurn, &splashOutBlendHardLight, &splashOutBlendSoftLight, &splashOutBlendDifference, &splashOutBlendExclusion, &splashOutBlendHue, &splashOutBlendSaturation, &splashOutBlendColor, &splashOutBlendLuminosity }; //------------------------------------------------------------------------ // SplashOutFontFileID //------------------------------------------------------------------------ class SplashOutFontFileID: public SplashFontFileID { public: SplashOutFontFileID(Ref *rA) { r = *rA; substIdx = -1; } ~SplashOutFontFileID() {} GBool matches(SplashFontFileID *id) { return ((SplashOutFontFileID *)id)->r.num == r.num && ((SplashOutFontFileID *)id)->r.gen == r.gen; } void setSubstIdx(int substIdxA) { substIdx = substIdxA; } int getSubstIdx() { return substIdx; } private: Ref r; int substIdx; }; //------------------------------------------------------------------------ // T3FontCache //------------------------------------------------------------------------ struct T3FontCacheTag { Gushort code; Gushort mru; // valid bit (0x8000) and MRU index }; class T3FontCache { public: T3FontCache(Ref *fontID, double m11A, double m12A, double m21A, double m22A, int glyphXA, int glyphYA, int glyphWA, int glyphHA, GBool aa, GBool validBBoxA); ~T3FontCache(); GBool matches(Ref *idA, double m11A, double m12A, double m21A, double m22A) { return fontID.num == idA->num && fontID.gen == idA->gen && m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } Ref fontID; // PDF font ID double m11, m12, m21, m22; // transform matrix int glyphX, glyphY; // pixel offset of glyph bitmaps int glyphW, glyphH; // size of glyph bitmaps, in pixels GBool validBBox; // false if the bbox was [0 0 0 0] int glyphSize; // size of glyph bitmaps, in bytes int cacheSets; // number of sets in cache int cacheAssoc; // cache associativity (glyphs per set) Guchar *cacheData; // glyph pixmap cache T3FontCacheTag *cacheTags; // cache tags, i.e., char codes }; T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, double m21A, double m22A, int glyphXA, int glyphYA, int glyphWA, int glyphHA, GBool validBBoxA, GBool aa) { int i; fontID = *fontIDA; m11 = m11A; m12 = m12A; m21 = m21A; m22 = m22A; glyphX = glyphXA; glyphY = glyphYA; glyphW = glyphWA; glyphH = glyphHA; validBBox = validBBoxA; // sanity check for excessively large glyphs (which most likely // indicate an incorrect BBox) i = glyphW * glyphH; if (i > 100000 || glyphW > INT_MAX / glyphH || glyphW <= 0 || glyphH <= 0) { glyphW = glyphH = 100; validBBox = gFalse; } if (aa) { glyphSize = glyphW * glyphH; } else { glyphSize = ((glyphW + 7) >> 3) * glyphH; } cacheAssoc = type3FontCacheAssoc; for (cacheSets = type3FontCacheMaxSets; cacheSets > 1 && cacheSets * cacheAssoc * glyphSize > type3FontCacheSize; cacheSets >>= 1) ; cacheData = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); cacheTags = (T3FontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(T3FontCacheTag)); for (i = 0; i < cacheSets * cacheAssoc; ++i) { cacheTags[i].mru = i & (cacheAssoc - 1); } } T3FontCache::~T3FontCache() { gfree(cacheData); gfree(cacheTags); } struct T3GlyphStack { Gushort code; // character code //----- cache info T3FontCache *cache; // font cache for the current font T3FontCacheTag *cacheTag; // pointer to cache tag for the glyph Guchar *cacheData; // pointer to cache data for the glyph //----- saved state SplashBitmap *origBitmap; Splash *origSplash; double origCTM4, origCTM5; T3GlyphStack *next; // next object on stack }; //------------------------------------------------------------------------ // SplashTransparencyGroup //------------------------------------------------------------------------ struct SplashTransparencyGroup { int tx, ty; // translation coordinates SplashBitmap *tBitmap; // bitmap for transparency group GfxColorSpace *blendingColorSpace; GBool isolated; //----- saved state SplashBitmap *origBitmap; Splash *origSplash; SplashTransparencyGroup *next; }; //------------------------------------------------------------------------ // SplashOutputDev //------------------------------------------------------------------------ SplashOutputDev::SplashOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool bitmapTopDownA, GBool allowAntialiasA) { colorMode = colorModeA; bitmapRowPad = bitmapRowPadA; bitmapTopDown = bitmapTopDownA; bitmapUpsideDown = gFalse; allowAntialias = allowAntialiasA; vectorAntialias = allowAntialias && globalParams->getVectorAntialias() && colorMode != splashModeMono1; setupScreenParams(72.0, 72.0); reverseVideo = reverseVideoA; splashColorCopy(paperColor, paperColorA); skipHorizText = gFalse; skipRotatedText = gFalse; xref = NULL; bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, colorMode != splashModeMono1, bitmapTopDown); splash = new Splash(bitmap, vectorAntialias, &screenParams); splash->setMinLineWidth(globalParams->getMinLineWidth()); splash->clear(paperColor, 0); fontEngine = NULL; nT3Fonts = 0; t3GlyphStack = NULL; font = NULL; needFontUpdate = gFalse; textClipPath = NULL; transpGroupStack = NULL; nestCount = 0; } void SplashOutputDev::setupScreenParams(double hDPI, double vDPI) { screenParams.size = globalParams->getScreenSize(); screenParams.dotRadius = globalParams->getScreenDotRadius(); screenParams.gamma = (SplashCoord)globalParams->getScreenGamma(); screenParams.blackThreshold = (SplashCoord)globalParams->getScreenBlackThreshold(); screenParams.whiteThreshold = (SplashCoord)globalParams->getScreenWhiteThreshold(); switch (globalParams->getScreenType()) { case screenDispersed: screenParams.type = splashScreenDispersed; if (screenParams.size < 0) { screenParams.size = 4; } break; case screenClustered: screenParams.type = splashScreenClustered; if (screenParams.size < 0) { screenParams.size = 10; } break; case screenStochasticClustered: screenParams.type = splashScreenStochasticClustered; if (screenParams.size < 0) { screenParams.size = 64; } if (screenParams.dotRadius < 0) { screenParams.dotRadius = 2; } break; case screenUnset: default: // use clustered dithering for resolution >= 300 dpi // (compare to 299.9 to avoid floating point issues) if (hDPI > 299.9 && vDPI > 299.9) { screenParams.type = splashScreenStochasticClustered; if (screenParams.size < 0) { screenParams.size = 64; } if (screenParams.dotRadius < 0) { screenParams.dotRadius = 2; } } else { screenParams.type = splashScreenDispersed; if (screenParams.size < 0) { screenParams.size = 4; } } } } SplashOutputDev::~SplashOutputDev() { int i; for (i = 0; i < nT3Fonts; ++i) { delete t3FontCache[i]; } if (fontEngine) { delete fontEngine; } if (splash) { delete splash; } if (bitmap) { delete bitmap; } } void SplashOutputDev::startDoc(XRef *xrefA) { int i; xref = xrefA; if (fontEngine) { delete fontEngine; } fontEngine = new SplashFontEngine( #if HAVE_T1LIB_H globalParams->getEnableT1lib(), #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H globalParams->getEnableFreeType(), globalParams->getDisableFreeTypeHinting() ? splashFTNoHinting : 0, #endif allowAntialias && globalParams->getAntialias() && colorMode != splashModeMono1); for (i = 0; i < nT3Fonts; ++i) { delete t3FontCache[i]; } nT3Fonts = 0; } void SplashOutputDev::startPage(int pageNum, GfxState *state) { int w, h; double *ctm; SplashCoord mat[6]; SplashColor color; if (state) { setupScreenParams(state->getHDPI(), state->getVDPI()); w = (int)(state->getPageWidth() + 0.5); if (w <= 0) { w = 1; } h = (int)(state->getPageHeight() + 0.5); if (h <= 0) { h = 1; } } else { w = h = 1; } if (splash) { delete splash; splash = NULL; } if (!bitmap || w != bitmap->getWidth() || h != bitmap->getHeight()) { if (bitmap) { delete bitmap; bitmap = NULL; } bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, colorMode != splashModeMono1, bitmapTopDown); } splash = new Splash(bitmap, vectorAntialias, &screenParams); splash->setMinLineWidth(globalParams->getMinLineWidth()); if (state) { ctm = state->getCTM(); mat[0] = (SplashCoord)ctm[0]; mat[1] = (SplashCoord)ctm[1]; mat[2] = (SplashCoord)ctm[2]; mat[3] = (SplashCoord)ctm[3]; mat[4] = (SplashCoord)ctm[4]; mat[5] = (SplashCoord)ctm[5]; splash->setMatrix(mat); } switch (colorMode) { case splashModeMono1: case splashModeMono8: color[0] = 0; break; case splashModeRGB8: case splashModeBGR8: color[0] = color[1] = color[2] = 0; break; #if SPLASH_CMYK case splashModeCMYK8: color[0] = color[1] = color[2] = color[3] = 0; break; #endif } splash->setStrokePattern(new SplashSolidColor(color)); splash->setFillPattern(new SplashSolidColor(color)); splash->setLineCap(splashLineCapButt); splash->setLineJoin(splashLineJoinMiter); splash->setLineDash(NULL, 0, 0); splash->setMiterLimit(10); splash->setFlatness(1); // the SA parameter supposedly defaults to false, but Acrobat // apparently hardwires it to true splash->setStrokeAdjust(globalParams->getStrokeAdjust()); splash->clear(paperColor, 0); } void SplashOutputDev::endPage() { if (colorMode != splashModeMono1) { splash->compositeBackground(paperColor); } } void SplashOutputDev::saveState(GfxState *state) { splash->saveState(); } void SplashOutputDev::restoreState(GfxState *state) { splash->restoreState(); needFontUpdate = gTrue; } void SplashOutputDev::updateAll(GfxState *state) { updateLineDash(state); updateLineJoin(state); updateLineCap(state); updateLineWidth(state); updateFlatness(state); updateMiterLimit(state); updateStrokeAdjust(state); updateFillColor(state); updateStrokeColor(state); needFontUpdate = gTrue; } void SplashOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) { double *ctm; SplashCoord mat[6]; ctm = state->getCTM(); mat[0] = (SplashCoord)ctm[0]; mat[1] = (SplashCoord)ctm[1]; mat[2] = (SplashCoord)ctm[2]; mat[3] = (SplashCoord)ctm[3]; mat[4] = (SplashCoord)ctm[4]; mat[5] = (SplashCoord)ctm[5]; splash->setMatrix(mat); } void SplashOutputDev::updateLineDash(GfxState *state) { double *dashPattern; int dashLength; double dashStart; SplashCoord dash[20]; int i; state->getLineDash(&dashPattern, &dashLength, &dashStart); if (dashLength > 20) { dashLength = 20; } for (i = 0; i < dashLength; ++i) { dash[i] = (SplashCoord)dashPattern[i]; if (dash[i] < 0) { dash[i] = 0; } } splash->setLineDash(dash, dashLength, (SplashCoord)dashStart); } void SplashOutputDev::updateFlatness(GfxState *state) { #if 0 // Acrobat ignores the flatness setting, and always renders curves // with a fairly small flatness value splash->setFlatness(state->getFlatness()); #endif } void SplashOutputDev::updateLineJoin(GfxState *state) { splash->setLineJoin(state->getLineJoin()); } void SplashOutputDev::updateLineCap(GfxState *state) { splash->setLineCap(state->getLineCap()); } void SplashOutputDev::updateMiterLimit(GfxState *state) { splash->setMiterLimit(state->getMiterLimit()); } void SplashOutputDev::updateLineWidth(GfxState *state) { splash->setLineWidth(state->getLineWidth()); } void SplashOutputDev::updateStrokeAdjust(GfxState *state) { #if 0 // the SA parameter supposedly defaults to false, but Acrobat // apparently hardwires it to true splash->setStrokeAdjust(state->getStrokeAdjust()); #endif } void SplashOutputDev::updateFillColor(GfxState *state) { GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif switch (colorMode) { case splashModeMono1: case splashModeMono8: state->getFillGray(&gray); splash->setFillPattern(getColor(gray)); break; case splashModeRGB8: case splashModeBGR8: state->getFillRGB(&rgb); splash->setFillPattern(getColor(&rgb)); break; #if SPLASH_CMYK case splashModeCMYK8: state->getFillCMYK(&cmyk); splash->setFillPattern(getColor(&cmyk)); break; #endif } } void SplashOutputDev::updateStrokeColor(GfxState *state) { GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif switch (colorMode) { case splashModeMono1: case splashModeMono8: state->getStrokeGray(&gray); splash->setStrokePattern(getColor(gray)); break; case splashModeRGB8: case splashModeBGR8: state->getStrokeRGB(&rgb); splash->setStrokePattern(getColor(&rgb)); break; #if SPLASH_CMYK case splashModeCMYK8: state->getStrokeCMYK(&cmyk); splash->setStrokePattern(getColor(&cmyk)); break; #endif } } SplashPattern *SplashOutputDev::getColor(GfxGray gray) { SplashColor color; if (reverseVideo) { gray = gfxColorComp1 - gray; } color[0] = colToByte(gray); return new SplashSolidColor(color); } SplashPattern *SplashOutputDev::getColor(GfxRGB *rgb) { GfxColorComp r, g, b; SplashColor color; if (reverseVideo) { r = gfxColorComp1 - rgb->r; g = gfxColorComp1 - rgb->g; b = gfxColorComp1 - rgb->b; } else { r = rgb->r; g = rgb->g; b = rgb->b; } color[0] = colToByte(r); color[1] = colToByte(g); color[2] = colToByte(b); return new SplashSolidColor(color); } #if SPLASH_CMYK SplashPattern *SplashOutputDev::getColor(GfxCMYK *cmyk) { SplashColor color; color[0] = colToByte(cmyk->c); color[1] = colToByte(cmyk->m); color[2] = colToByte(cmyk->y); color[3] = colToByte(cmyk->k); return new SplashSolidColor(color); } #endif void SplashOutputDev::setOverprintMask(GfxColorSpace *colorSpace, GBool overprintFlag, int overprintMode, GfxColor *singleColor) { #if SPLASH_CMYK Guint mask; GfxCMYK cmyk; if (overprintFlag && globalParams->getOverprintPreview()) { mask = colorSpace->getOverprintMask(); if (singleColor && overprintMode && (colorSpace->getMode() == csDeviceCMYK || (colorSpace->getMode() == csICCBased && colorSpace->getNComps() == 4))) { colorSpace->getCMYK(singleColor, &cmyk); if (cmyk.c == 0) { mask &= ~1; } if (cmyk.m == 0) { mask &= ~2; } if (cmyk.y == 0) { mask &= ~4; } if (cmyk.k == 0) { mask &= ~8; } } } else { mask = 0xffffffff; } splash->setOverprintMask(mask); #endif } void SplashOutputDev::updateBlendMode(GfxState *state) { splash->setBlendFunc(splashOutBlendFuncs[state->getBlendMode()]); } void SplashOutputDev::updateFillOpacity(GfxState *state) { splash->setFillAlpha((SplashCoord)state->getFillOpacity()); } void SplashOutputDev::updateStrokeOpacity(GfxState *state) { splash->setStrokeAlpha((SplashCoord)state->getStrokeOpacity()); } void SplashOutputDev::updateTransfer(GfxState *state) { Function **transfer; Guchar red[256], green[256], blue[256], gray[256]; double x, y; int i; transfer = state->getTransfer(); if (transfer[0] && transfer[0]->getInputSize() == 1 && transfer[0]->getOutputSize() == 1) { if (transfer[1] && transfer[1]->getInputSize() == 1 && transfer[1]->getOutputSize() == 1 && transfer[2] && transfer[2]->getInputSize() == 1 && transfer[2]->getOutputSize() == 1 && transfer[3] && transfer[3]->getInputSize() == 1 && transfer[3]->getOutputSize() == 1) { for (i = 0; i < 256; ++i) { x = i / 255.0; transfer[0]->transform(&x, &y); red[i] = (Guchar)(y * 255.0 + 0.5); transfer[1]->transform(&x, &y); green[i] = (Guchar)(y * 255.0 + 0.5); transfer[2]->transform(&x, &y); blue[i] = (Guchar)(y * 255.0 + 0.5); transfer[3]->transform(&x, &y); gray[i] = (Guchar)(y * 255.0 + 0.5); } } else { for (i = 0; i < 256; ++i) { x = i / 255.0; transfer[0]->transform(&x, &y); red[i] = green[i] = blue[i] = gray[i] = (Guchar)(y * 255.0 + 0.5); } } } else { for (i = 0; i < 256; ++i) { red[i] = green[i] = blue[i] = gray[i] = (Guchar)i; } } splash->setTransfer(red, green, blue, gray); } void SplashOutputDev::updateFont(GfxState *state) { needFontUpdate = gTrue; } void SplashOutputDev::doUpdateFont(GfxState *state) { GfxFont *gfxFont; GfxFontLoc *fontLoc; GfxFontType fontType; SplashOutFontFileID *id; SplashFontFile *fontFile; int fontNum; FoFiTrueType *ff; Ref embRef; Object refObj, strObj; GString *tmpFileName, *fileName; FILE *tmpFile; int *codeToGID; CharCodeToUnicode *ctu; double *textMat; double m11, m12, m21, m22, fontSize; double w, fontScaleMin, fontScaleAvg, fontScale; Gushort ww; SplashCoord mat[4]; char *name; Unicode uBuf[8]; int c, substIdx, n, code, cmap, i; needFontUpdate = gFalse; font = NULL; tmpFileName = NULL; substIdx = -1; if (!(gfxFont = state->getFont())) { goto err1; } fontType = gfxFont->getType(); if (fontType == fontType3) { goto err1; } // sanity-check the font size - skip anything larger than 10 inches // (this avoids problems allocating memory for the font cache) if (state->getTransformedFontSize() > 10 * (state->getHDPI() + state->getVDPI())) { goto err1; } // check the font file cache id = new SplashOutFontFileID(gfxFont->getID()); if ((fontFile = fontEngine->getFontFile(id))) { delete id; } else { fileName = NULL; fontNum = 0; if (!(fontLoc = gfxFont->locateFont(xref, gFalse))) { error(errSyntaxError, -1, "Couldn't find a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); goto err2; } // embedded font if (fontLoc->locType == gfxFontLocEmbedded) { gfxFont->getEmbeddedFontID(&embRef); if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { error(errIO, -1, "Couldn't create temporary font file"); delete fontLoc; goto err2; } refObj.initRef(embRef.num, embRef.gen); refObj.fetch(xref, &strObj); refObj.free(); if (!strObj.isStream()) { error(errSyntaxError, -1, "Embedded font object is wrong type"); strObj.free(); fclose(tmpFile); delete fontLoc; goto err2; } strObj.streamReset(); while ((c = strObj.streamGetChar()) != EOF) { fputc(c, tmpFile); } strObj.streamClose(); strObj.free(); fclose(tmpFile); fileName = tmpFileName; // external font } else { // gfxFontLocExternal fileName = fontLoc->path; fontNum = fontLoc->fontNum; if (fontLoc->substIdx >= 0) { id->setSubstIdx(fontLoc->substIdx); } } // load the font file switch (fontLoc->fontType) { case fontType1: if (!(fontFile = fontEngine->loadType1Font( id, fileName->getCString(), fileName == tmpFileName, (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontType1C: if (!(fontFile = fontEngine->loadType1CFont( id, fileName->getCString(), fileName == tmpFileName, (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontType1COT: if (!(fontFile = fontEngine->loadOpenTypeT1CFont( id, fileName->getCString(), fileName == tmpFileName, (const char **)((Gfx8BitFont *)gfxFont)->getEncoding()))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontTrueType: case fontTrueTypeOT: if ((ff = FoFiTrueType::load(fileName->getCString()))) { codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); n = 256; delete ff; // if we're substituting for a non-TrueType font, we need to mark // all notdef codes as "do not draw" (rather than drawing TrueType // notdef glyphs) if (gfxFont->getType() != fontTrueType && gfxFont->getType() != fontTrueTypeOT) { for (i = 0; i < 256; ++i) { if (codeToGID[i] == 0) { codeToGID[i] = -1; } } } } else { codeToGID = NULL; n = 0; } if (!(fontFile = fontEngine->loadTrueTypeFont( id, fileName->getCString(), fontNum, fileName == tmpFileName, codeToGID, n, gfxFont->getEmbeddedFontName() ? gfxFont->getEmbeddedFontName()->getCString() : (char *)NULL))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontCIDType0: case fontCIDType0C: if (!(fontFile = fontEngine->loadCIDFont( id, fileName->getCString(), fileName == tmpFileName))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontCIDType0COT: if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); codeToGID = (int *)gmallocn(n, sizeof(int)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(int)); } else { codeToGID = NULL; n = 0; } if (!(fontFile = fontEngine->loadOpenTypeCFFFont( id, fileName->getCString(), fileName == tmpFileName, codeToGID, n))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; case fontCIDType2: case fontCIDType2OT: codeToGID = NULL; n = 0; if (fontLoc->locType == gfxFontLocEmbedded) { if (((GfxCIDFont *)gfxFont)->getCIDToGID()) { n = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(); codeToGID = (int *)gmallocn(n, sizeof(int)); memcpy(codeToGID, ((GfxCIDFont *)gfxFont)->getCIDToGID(), n * sizeof(int)); } } else { // create a CID-to-GID mapping, via Unicode if ((ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) { //~ this should use fontNum to load the correct font if ((ff = FoFiTrueType::load(fileName->getCString()))) { // look for a Unicode cmap for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { if ((ff->getCmapPlatform(cmap) == 3 && ff->getCmapEncoding(cmap) == 1) || ff->getCmapPlatform(cmap) == 0) { break; } } if (cmap < ff->getNumCmaps()) { // map CID -> Unicode -> GID n = ctu->getLength(); codeToGID = (int *)gmallocn(n, sizeof(int)); for (code = 0; code < n; ++code) { if (ctu->mapToUnicode(code, uBuf, 8) > 0) { codeToGID[code] = ff->mapCodeToGID(cmap, uBuf[0]); } else { codeToGID[code] = -1; } } } delete ff; } ctu->decRefCnt(); } else { error(errSyntaxError, -1, "Couldn't find a mapping to Unicode for font '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); } } if (!(fontFile = fontEngine->loadTrueTypeFont( id, fileName->getCString(), fontNum, fileName == tmpFileName, codeToGID, n, gfxFont->getEmbeddedFontName() ? gfxFont->getEmbeddedFontName()->getCString() : (char *)NULL))) { error(errSyntaxError, -1, "Couldn't create a font for '{0:s}'", gfxFont->getName() ? gfxFont->getName()->getCString() : "(unnamed)"); delete fontLoc; goto err2; } break; default: // this shouldn't happen goto err2; } delete fontLoc; } // get the font matrix textMat = state->getTextMat(); fontSize = state->getFontSize(); m11 = textMat[0] * fontSize * state->getHorizScaling(); m12 = textMat[1] * fontSize * state->getHorizScaling(); m21 = textMat[2] * fontSize; m22 = textMat[3] * fontSize; // for substituted fonts: adjust the font matrix -- compare the // widths of letters and digits (A-Z, a-z, 0-9) in the original font // and the substituted font substIdx = ((SplashOutFontFileID *)fontFile->getID())->getSubstIdx(); if (substIdx >= 0 && substIdx < 12) { fontScaleMin = 1; fontScaleAvg = 0; n = 0; for (code = 0; code < 256; ++code) { if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && name[0] && !name[1] && ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z') || (name[0] >= '0' && name[0] <= '9'))) { w = ((Gfx8BitFont *)gfxFont)->getWidth(code); builtinFontSubst[substIdx]->widths->getWidth(name, &ww); if (w > 0.01 && ww > 10) { w /= ww * 0.001; if (w < fontScaleMin) { fontScaleMin = w; } fontScaleAvg += w; ++n; } } } // if real font is narrower than substituted font, reduce the font // size accordingly -- this currently uses a scale factor halfway // between the minimum and average computed scale factors, which // is a bit of a kludge, but seems to produce mostly decent // results if (n) { fontScaleAvg /= n; if (fontScaleAvg < 1) { fontScale = 0.5 * (fontScaleMin + fontScaleAvg); m11 *= fontScale; m12 *= fontScale; } } } // create the scaled font mat[0] = m11; mat[1] = m12; mat[2] = m21; mat[3] = m22; font = fontEngine->getFont(fontFile, mat, splash->getMatrix()); if (tmpFileName) { delete tmpFileName; } return; err2: delete id; err1: if (tmpFileName) { unlink(tmpFileName->getCString()); delete tmpFileName; } return; } void SplashOutputDev::stroke(GfxState *state) { SplashPath *path; if (state->getStrokeColorSpace()->isNonMarking()) { return; } setOverprintMask(state->getStrokeColorSpace(), state->getStrokeOverprint(), state->getOverprintMode(), state->getStrokeColor()); path = convertPath(state, state->getPath(), gFalse); splash->stroke(path); delete path; } void SplashOutputDev::fill(GfxState *state) { SplashPath *path; if (state->getFillColorSpace()->isNonMarking()) { return; } setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); path = convertPath(state, state->getPath(), gTrue); splash->fill(path, gFalse); delete path; } void SplashOutputDev::eoFill(GfxState *state) { SplashPath *path; if (state->getFillColorSpace()->isNonMarking()) { return; } setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); path = convertPath(state, state->getPath(), gTrue); splash->fill(path, gTrue); delete path; } void SplashOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) { double tileXMin, tileYMin, tileXMax, tileYMax, tx, ty; int tileX0, tileY0, tileW, tileH, tileSize; SplashBitmap *origBitmap, *tileBitmap; Splash *origSplash; SplashColor color; double mat1[6]; double xa, ya, xb, yb, xc, yc; int x, y, xx, yy, i; // transform the four corners of the bbox from pattern space to // device space and compute the device space bbox state->transform(bbox[0] * mat[0] + bbox[1] * mat[2] + mat[4], bbox[0] * mat[1] + bbox[1] * mat[3] + mat[5], &tx, &ty); tileXMin = tileXMax = tx; tileYMin = tileYMax = ty; state->transform(bbox[2] * mat[0] + bbox[1] * mat[2] + mat[4], bbox[2] * mat[1] + bbox[1] * mat[3] + mat[5], &tx, &ty); if (tx < tileXMin) { tileXMin = tx; } else if (tx > tileXMax) { tileXMax = tx; } if (ty < tileYMin) { tileYMin = ty; } else if (ty > tileYMax) { tileYMax = ty; } state->transform(bbox[2] * mat[0] + bbox[3] * mat[2] + mat[4], bbox[2] * mat[1] + bbox[3] * mat[3] + mat[5], &tx, &ty); if (tx < tileXMin) { tileXMin = tx; } else if (tx > tileXMax) { tileXMax = tx; } if (ty < tileYMin) { tileYMin = ty; } else if (ty > tileYMax) { tileYMax = ty; } state->transform(bbox[0] * mat[0] + bbox[3] * mat[2] + mat[4], bbox[0] * mat[1] + bbox[3] * mat[3] + mat[5], &tx, &ty); if (tx < tileXMin) { tileXMin = tx; } else if (tx > tileXMax) { tileXMax = tx; } if (ty < tileYMin) { tileYMin = ty; } else if (ty > tileYMax) { tileYMax = ty; } if (tileXMin == tileXMax || tileYMin == tileYMax) { return; } tileX0 = (int)floor(tileXMin); tileY0 = (int)floor(tileYMin); tileW = (int)ceil(tileXMax) - tileX0; tileH = (int)ceil(tileYMax) - tileY0; // check for an excessively large tile size tileSize = tileW * tileH; if (tileSize > 1000000 || tileSize < 0) { mat1[0] = mat[0]; mat1[1] = mat[1]; mat1[2] = mat[2]; mat1[3] = mat[3]; for (y = y0; y < y1; ++y) { for (x = x0; x < x1; ++x) { xa = x * xStep; ya = y * yStep; mat1[4] = xa * mat[0] + ya * mat[2] + mat[4]; mat1[5] = xa * mat[1] + ya * mat[3] + mat[5]; gfx->drawForm(str, resDict, mat1, bbox); } } return; } // create a temporary bitmap origBitmap = bitmap; origSplash = splash; bitmap = tileBitmap = new SplashBitmap(tileW, tileH, bitmapRowPad, colorMode, gTrue, bitmapTopDown); splash = new Splash(bitmap, vectorAntialias, origSplash->getScreen()); splash->setMinLineWidth(globalParams->getMinLineWidth()); for (i = 0; i < splashMaxColorComps; ++i) { color[i] = 0; } splash->clear(color); ++nestCount; // copy the fill color (for uncolored tiling patterns) // (and stroke color, to handle buggy PDF files) splash->setFillPattern(origSplash->getFillPattern()->copy()); splash->setStrokePattern(origSplash->getStrokePattern()->copy()); // render the tile state->shiftCTM(-tileX0, -tileY0); updateCTM(state, 0, 0, 0, 0, 0, 0); gfx->drawForm(str, resDict, mat, bbox); state->shiftCTM(tileX0, tileY0); updateCTM(state, 0, 0, 0, 0, 0, 0); // restore the original bitmap --nestCount; delete splash; bitmap = origBitmap; splash = origSplash; splash->setOverprintMask(0xffffffff); // draw the tiles for (y = y0; y < y1; ++y) { for (x = x0; x < x1; ++x) { xa = x * xStep; ya = y * yStep; xb = xa * mat[0] + ya * mat[2]; yb = xa * mat[1] + ya * mat[3]; state->transformDelta(xb, yb, &xc, &yc); xx = (int)(xc + tileX0 + 0.5); yy = (int)(yc + tileY0 + 0.5); splash->composite(tileBitmap, 0, 0, xx, yy, tileW, tileH, gFalse, gFalse); } } delete tileBitmap; } void SplashOutputDev::clip(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath(), gTrue); splash->clipToPath(path, gFalse); delete path; } void SplashOutputDev::eoClip(GfxState *state) { SplashPath *path; path = convertPath(state, state->getPath(), gTrue); splash->clipToPath(path, gTrue); delete path; } void SplashOutputDev::clipToStrokePath(GfxState *state) { SplashPath *path, *path2; path = convertPath(state, state->getPath(), gFalse); path2 = splash->makeStrokePath(path, state->getLineWidth()); delete path; splash->clipToPath(path2, gFalse); delete path2; } SplashPath *SplashOutputDev::convertPath(GfxState *state, GfxPath *path, GBool dropEmptySubpaths) { SplashPath *sPath; GfxSubpath *subpath; int n, i, j; n = dropEmptySubpaths ? 1 : 0; sPath = new SplashPath(); for (i = 0; i < path->getNumSubpaths(); ++i) { subpath = path->getSubpath(i); if (subpath->getNumPoints() > n) { sPath->moveTo((SplashCoord)subpath->getX(0), (SplashCoord)subpath->getY(0)); j = 1; while (j < subpath->getNumPoints()) { if (subpath->getCurve(j)) { sPath->curveTo((SplashCoord)subpath->getX(j), (SplashCoord)subpath->getY(j), (SplashCoord)subpath->getX(j+1), (SplashCoord)subpath->getY(j+1), (SplashCoord)subpath->getX(j+2), (SplashCoord)subpath->getY(j+2)); j += 3; } else { sPath->lineTo((SplashCoord)subpath->getX(j), (SplashCoord)subpath->getY(j)); ++j; } } if (subpath->isClosed()) { sPath->close(); } } } return sPath; } void SplashOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) { SplashPath *path; int render; GBool doFill, doStroke, doClip, strokeAdjust; double m[4]; GBool horiz; if (skipHorizText || skipRotatedText) { state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); horiz = m[0] > 0 && fabs(m[1]) < 0.001 && fabs(m[2]) < 0.001 && m[3] < 0; if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) { return; } } // check for invisible text -- this is used by Acrobat Capture render = state->getRender(); if (render == 3) { return; } if (needFontUpdate) { doUpdateFont(state); } if (!font) { return; } x -= originX; y -= originY; doFill = !(render & 1) && !state->getFillColorSpace()->isNonMarking(); doStroke = ((render & 3) == 1 || (render & 3) == 2) && !state->getStrokeColorSpace()->isNonMarking(); doClip = render & 4; path = NULL; if (doStroke || doClip) { if ((path = font->getGlyphPath(code))) { path->offset((SplashCoord)x, (SplashCoord)y); } } // don't use stroke adjustment when stroking text -- the results // tend to be ugly (because characters with horizontal upper or // lower edges get misaligned relative to the other characters) strokeAdjust = gFalse; // make gcc happy if (doStroke) { strokeAdjust = splash->getStrokeAdjust(); splash->setStrokeAdjust(gFalse); } // fill and stroke if (doFill && doStroke) { if (path) { setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); splash->fill(path, gFalse); setOverprintMask(state->getStrokeColorSpace(), state->getStrokeOverprint(), state->getOverprintMode(), state->getStrokeColor()); splash->stroke(path); } // fill } else if (doFill) { setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); splash->fillChar((SplashCoord)x, (SplashCoord)y, code, font); // stroke } else if (doStroke) { if (path) { setOverprintMask(state->getStrokeColorSpace(), state->getStrokeOverprint(), state->getOverprintMode(), state->getStrokeColor()); splash->stroke(path); } } // clip if (doClip) { if (path) { if (textClipPath) { textClipPath->append(path); } else { textClipPath = path; path = NULL; } } } if (doStroke) { splash->setStrokeAdjust(strokeAdjust); } if (path) { delete path; } } GBool SplashOutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { GfxFont *gfxFont; Ref *fontID; double *ctm, *bbox; T3FontCache *t3Font; T3GlyphStack *t3gs; GBool validBBox; double m[4]; GBool horiz; double x1, y1, xMin, yMin, xMax, yMax, xt, yt; int i, j; if (skipHorizText || skipRotatedText) { state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); horiz = m[0] > 0 && fabs(m[1]) < 0.001 && fabs(m[2]) < 0.001 && m[3] < 0; if ((skipHorizText && horiz) || (skipRotatedText && !horiz)) { return gTrue; } } if (!(gfxFont = state->getFont())) { return gFalse; } fontID = gfxFont->getID(); ctm = state->getCTM(); state->transform(0, 0, &xt, &yt); // is it the first (MRU) font in the cache? if (!(nT3Fonts > 0 && t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { // is the font elsewhere in the cache? for (i = 1; i < nT3Fonts; ++i) { if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { t3Font = t3FontCache[i]; for (j = i; j > 0; --j) { t3FontCache[j] = t3FontCache[j - 1]; } t3FontCache[0] = t3Font; break; } } if (i >= nT3Fonts) { // create new entry in the font cache if (nT3Fonts == splashOutT3FontCacheSize) { delete t3FontCache[nT3Fonts - 1]; --nT3Fonts; } for (j = nT3Fonts; j > 0; --j) { t3FontCache[j] = t3FontCache[j - 1]; } ++nT3Fonts; bbox = gfxFont->getFontBBox(); if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { // unspecified bounding box -- just take a guess xMin = xt - 5; xMax = xMin + 30; yMax = yt + 15; yMin = yMax - 45; validBBox = gFalse; } else { state->transform(bbox[0], bbox[1], &x1, &y1); xMin = xMax = x1; yMin = yMax = y1; state->transform(bbox[0], bbox[3], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(bbox[2], bbox[1], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(bbox[2], bbox[3], &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } validBBox = gTrue; } t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], (int)floor(xMin - xt) - 2, (int)floor(yMin - yt) - 2, (int)ceil(xMax) - (int)floor(xMin) + 4, (int)ceil(yMax) - (int)floor(yMin) + 4, validBBox, colorMode != splashModeMono1); } } t3Font = t3FontCache[0]; // is the glyph in the cache? i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; for (j = 0; j < t3Font->cacheAssoc; ++j) { if ((t3Font->cacheTags[i+j].mru & 0x8000) && t3Font->cacheTags[i+j].code == code) { drawType3Glyph(state, t3Font, &t3Font->cacheTags[i+j], t3Font->cacheData + (i+j) * t3Font->glyphSize); return gTrue; } } // push a new Type 3 glyph record t3gs = new T3GlyphStack(); t3gs->next = t3GlyphStack; t3GlyphStack = t3gs; t3GlyphStack->code = code; t3GlyphStack->cache = t3Font; t3GlyphStack->cacheTag = NULL; t3GlyphStack->cacheData = NULL; haveT3Dx = gFalse; return gFalse; } void SplashOutputDev::endType3Char(GfxState *state) { T3GlyphStack *t3gs; double *ctm; if (t3GlyphStack->cacheTag) { --nestCount; memcpy(t3GlyphStack->cacheData, bitmap->getDataPtr(), t3GlyphStack->cache->glyphSize); delete bitmap; delete splash; bitmap = t3GlyphStack->origBitmap; splash = t3GlyphStack->origSplash; ctm = state->getCTM(); state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); updateCTM(state, 0, 0, 0, 0, 0, 0); drawType3Glyph(state, t3GlyphStack->cache, t3GlyphStack->cacheTag, t3GlyphStack->cacheData); } t3gs = t3GlyphStack; t3GlyphStack = t3gs->next; delete t3gs; } void SplashOutputDev::type3D0(GfxState *state, double wx, double wy) { haveT3Dx = gTrue; } void SplashOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) { double *ctm; T3FontCache *t3Font; SplashColor color; double xt, yt, xMin, xMax, yMin, yMax, x1, y1; int i, j; // ignore multiple d0/d1 operators if (haveT3Dx) { return; } haveT3Dx = gTrue; t3Font = t3GlyphStack->cache; // check for a valid bbox state->transform(0, 0, &xt, &yt); state->transform(llx, lly, &x1, &y1); xMin = xMax = x1; yMin = yMax = y1; state->transform(llx, ury, &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(urx, lly, &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } state->transform(urx, ury, &x1, &y1); if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } if (xMin - xt < t3Font->glyphX || yMin - yt < t3Font->glyphY || xMax - xt > t3Font->glyphX + t3Font->glyphW || yMax - yt > t3Font->glyphY + t3Font->glyphH) { if (t3Font->validBBox) { error(errSyntaxWarning, -1, "Bad bounding box in Type 3 glyph"); } return; } // allocate a cache entry i = (t3GlyphStack->code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; for (j = 0; j < t3Font->cacheAssoc; ++j) { if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { t3Font->cacheTags[i+j].mru = 0x8000; t3Font->cacheTags[i+j].code = t3GlyphStack->code; t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; } else { ++t3Font->cacheTags[i+j].mru; } } // save state t3GlyphStack->origBitmap = bitmap; t3GlyphStack->origSplash = splash; ctm = state->getCTM(); t3GlyphStack->origCTM4 = ctm[4]; t3GlyphStack->origCTM5 = ctm[5]; // create the temporary bitmap if (colorMode == splashModeMono1) { bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, splashModeMono1, gFalse); splash = new Splash(bitmap, gFalse, t3GlyphStack->origSplash->getScreen()); color[0] = 0; splash->clear(color); color[0] = 0xff; } else { bitmap = new SplashBitmap(t3Font->glyphW, t3Font->glyphH, 1, splashModeMono8, gFalse); splash = new Splash(bitmap, vectorAntialias, t3GlyphStack->origSplash->getScreen()); color[0] = 0x00; splash->clear(color); color[0] = 0xff; } splash->setMinLineWidth(globalParams->getMinLineWidth()); splash->setFillPattern(new SplashSolidColor(color)); splash->setStrokePattern(new SplashSolidColor(color)); //~ this should copy other state from t3GlyphStack->origSplash? //~ [this is likely the same situation as in beginTransparencyGroup()] state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], -t3Font->glyphX, -t3Font->glyphY); updateCTM(state, 0, 0, 0, 0, 0, 0); ++nestCount; } void SplashOutputDev::drawType3Glyph(GfxState *state, T3FontCache *t3Font, T3FontCacheTag *tag, Guchar *data) { SplashGlyphBitmap glyph; setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); glyph.x = -t3Font->glyphX; glyph.y = -t3Font->glyphY; glyph.w = t3Font->glyphW; glyph.h = t3Font->glyphH; glyph.aa = colorMode != splashModeMono1; glyph.data = data; glyph.freeData = gFalse; splash->fillGlyph(0, 0, &glyph); } void SplashOutputDev::endTextObject(GfxState *state) { if (textClipPath) { splash->clipToPath(textClipPath, gFalse); delete textClipPath; textClipPath = NULL; } } struct SplashOutImageMaskData { ImageStream *imgStr; GBool invert; int width, height, y; }; GBool SplashOutputDev::imageMaskSrc(void *data, SplashColorPtr line) { SplashOutImageMaskData *imgMaskData = (SplashOutImageMaskData *)data; Guchar *p; SplashColorPtr q; int x; if (imgMaskData->y == imgMaskData->height) { return gFalse; } if (!(p = imgMaskData->imgStr->getLine())) { return gFalse; } for (x = 0, q = line; x < imgMaskData->width; ++x) { *q++ = *p++ ^ imgMaskData->invert; } ++imgMaskData->y; return gTrue; } void SplashOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { double *ctm; SplashCoord mat[6]; SplashOutImageMaskData imgMaskData; if (state->getFillColorSpace()->isNonMarking()) { return; } setOverprintMask(state->getFillColorSpace(), state->getFillOverprint(), state->getOverprintMode(), state->getFillColor()); ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; mat[2] = -ctm[2]; mat[3] = -ctm[3]; mat[4] = ctm[2] + ctm[4]; mat[5] = ctm[3] + ctm[5]; imgMaskData.imgStr = new ImageStream(str, width, 1, 1); imgMaskData.imgStr->reset(); imgMaskData.invert = invert ? 0 : 1; imgMaskData.width = width; imgMaskData.height = height; imgMaskData.y = 0; splash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, t3GlyphStack != NULL); if (inlineImg) { while (imgMaskData.y < height) { imgMaskData.imgStr->getLine(); ++imgMaskData.y; } } delete imgMaskData.imgStr; str->close(); } void SplashOutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { double *ctm; SplashCoord mat[6]; SplashOutImageMaskData imgMaskData; SplashBitmap *maskBitmap; Splash *maskSplash; SplashColor maskColor; ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; mat[2] = -ctm[2]; mat[3] = -ctm[3]; mat[4] = ctm[2] + ctm[4]; mat[5] = ctm[3] + ctm[5]; imgMaskData.imgStr = new ImageStream(str, width, 1, 1); imgMaskData.imgStr->reset(); imgMaskData.invert = invert ? 0 : 1; imgMaskData.width = width; imgMaskData.height = height; imgMaskData.y = 0; maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse); maskSplash = new Splash(maskBitmap, gTrue); maskColor[0] = 0; maskSplash->clear(maskColor); maskColor[0] = 0xff; maskSplash->setFillPattern(new SplashSolidColor(maskColor)); maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, width, height, mat, gFalse); delete imgMaskData.imgStr; str->close(); delete maskSplash; splash->setSoftMask(maskBitmap); } struct SplashOutImageData { ImageStream *imgStr; GfxImageColorMap *colorMap; SplashColorPtr lookup; int *maskColors; SplashColorMode colorMode; int width, height, y; }; GBool SplashOutputDev::imageSrc(void *data, SplashColorPtr colorLine, Guchar *alphaLine) { SplashOutImageData *imgData = (SplashOutImageData *)data; Guchar *p; SplashColorPtr q, col; GfxRGB rgb; GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; #endif int nComps, x; if (imgData->y == imgData->height) { return gFalse; } if (!(p = imgData->imgStr->getLine())) { return gFalse; } nComps = imgData->colorMap->getNumPixelComps(); if (imgData->lookup) { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) { *q++ = imgData->lookup[*p]; } break; case splashModeRGB8: case splashModeBGR8: for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) { col = &imgData->lookup[3 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; } break; #if SPLASH_CMYK case splashModeCMYK8: for (x = 0, q = colorLine; x < imgData->width; ++x, ++p) { col = &imgData->lookup[4 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; *q++ = col[3]; } break; #endif } } else { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) { imgData->colorMap->getGray(p, &gray); *q++ = colToByte(gray); } break; case splashModeRGB8: case splashModeBGR8: for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) { imgData->colorMap->getRGB(p, &rgb); *q++ = colToByte(rgb.r); *q++ = colToByte(rgb.g); *q++ = colToByte(rgb.b); } break; #if SPLASH_CMYK case splashModeCMYK8: for (x = 0, q = colorLine; x < imgData->width; ++x, p += nComps) { imgData->colorMap->getCMYK(p, &cmyk); *q++ = colToByte(cmyk.c); *q++ = colToByte(cmyk.m); *q++ = colToByte(cmyk.y); *q++ = colToByte(cmyk.k); } break; #endif } } ++imgData->y; return gTrue; } GBool SplashOutputDev::alphaImageSrc(void *data, SplashColorPtr colorLine, Guchar *alphaLine) { SplashOutImageData *imgData = (SplashOutImageData *)data; Guchar *p, *aq; SplashColorPtr q, col; GfxRGB rgb; GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; #endif Guchar alpha; int nComps, x, i; if (imgData->y == imgData->height) { return gFalse; } if (!(p = imgData->imgStr->getLine())) { return gFalse; } nComps = imgData->colorMap->getNumPixelComps(); for (x = 0, q = colorLine, aq = alphaLine; x < imgData->width; ++x, p += nComps) { alpha = 0; for (i = 0; i < nComps; ++i) { if (p[i] < imgData->maskColors[2*i] || p[i] > imgData->maskColors[2*i+1]) { alpha = 0xff; break; } } if (imgData->lookup) { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: *q++ = imgData->lookup[*p]; break; case splashModeRGB8: case splashModeBGR8: col = &imgData->lookup[3 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; break; #if SPLASH_CMYK case splashModeCMYK8: col = &imgData->lookup[4 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; *q++ = col[3]; break; #endif } *aq++ = alpha; } else { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: imgData->colorMap->getGray(p, &gray); *q++ = colToByte(gray); break; case splashModeRGB8: case splashModeBGR8: imgData->colorMap->getRGB(p, &rgb); *q++ = colToByte(rgb.r); *q++ = colToByte(rgb.g); *q++ = colToByte(rgb.b); break; #if SPLASH_CMYK case splashModeCMYK8: imgData->colorMap->getCMYK(p, &cmyk); *q++ = colToByte(cmyk.c); *q++ = colToByte(cmyk.m); *q++ = colToByte(cmyk.y); *q++ = colToByte(cmyk.k); break; #endif } *aq++ = alpha; } } ++imgData->y; return gTrue; } void SplashOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { double *ctm; SplashCoord mat[6]; SplashOutImageData imgData; SplashColorMode srcMode; SplashImageSource src; GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif Guchar pix; int n, i; setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), NULL); ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; mat[2] = -ctm[2]; mat[3] = -ctm[3]; mat[4] = ctm[2] + ctm[4]; mat[5] = ctm[3] + ctm[5]; imgData.imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgData.imgStr->reset(); imgData.colorMap = colorMap; imgData.maskColors = maskColors; imgData.colorMode = colorMode; imgData.width = width; imgData.height = height; imgData.y = 0; // special case for one-channel (monochrome/gray/separation) images: // build a lookup table here imgData.lookup = NULL; if (colorMap->getNumPixelComps() == 1) { n = 1 << colorMap->getBits(); switch (colorMode) { case splashModeMono1: case splashModeMono8: imgData.lookup = (SplashColorPtr)gmalloc(n); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getGray(&pix, &gray); imgData.lookup[i] = colToByte(gray); } break; case splashModeRGB8: case splashModeBGR8: imgData.lookup = (SplashColorPtr)gmallocn(n, 3); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getRGB(&pix, &rgb); imgData.lookup[3*i] = colToByte(rgb.r); imgData.lookup[3*i+1] = colToByte(rgb.g); imgData.lookup[3*i+2] = colToByte(rgb.b); } break; #if SPLASH_CMYK case splashModeCMYK8: imgData.lookup = (SplashColorPtr)gmallocn(n, 4); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getCMYK(&pix, &cmyk); imgData.lookup[4*i] = colToByte(cmyk.c); imgData.lookup[4*i+1] = colToByte(cmyk.m); imgData.lookup[4*i+2] = colToByte(cmyk.y); imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; #endif } } if (colorMode == splashModeMono1) { srcMode = splashModeMono8; } else { srcMode = colorMode; } src = maskColors ? &alphaImageSrc : &imageSrc; splash->drawImage(src, &imgData, srcMode, maskColors ? gTrue : gFalse, width, height, mat); if (inlineImg) { while (imgData.y < height) { imgData.imgStr->getLine(); ++imgData.y; } } gfree(imgData.lookup); delete imgData.imgStr; str->close(); } struct SplashOutMaskedImageData { ImageStream *imgStr; GfxImageColorMap *colorMap; SplashBitmap *mask; SplashColorPtr lookup; SplashColorMode colorMode; int width, height, y; }; GBool SplashOutputDev::maskedImageSrc(void *data, SplashColorPtr colorLine, Guchar *alphaLine) { SplashOutMaskedImageData *imgData = (SplashOutMaskedImageData *)data; Guchar *p, *aq; SplashColorPtr q, col; GfxRGB rgb; GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; #endif Guchar alpha; Guchar *maskPtr; int maskBit; int nComps, x; if (imgData->y == imgData->height) { return gFalse; } if (!(p = imgData->imgStr->getLine())) { return gFalse; } nComps = imgData->colorMap->getNumPixelComps(); maskPtr = imgData->mask->getDataPtr() + imgData->y * imgData->mask->getRowSize(); maskBit = 0x80; for (x = 0, q = colorLine, aq = alphaLine; x < imgData->width; ++x, p += nComps) { alpha = (*maskPtr & maskBit) ? 0xff : 0x00; if (!(maskBit >>= 1)) { ++maskPtr; maskBit = 0x80; } if (imgData->lookup) { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: *q++ = imgData->lookup[*p]; break; case splashModeRGB8: case splashModeBGR8: col = &imgData->lookup[3 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; break; #if SPLASH_CMYK case splashModeCMYK8: col = &imgData->lookup[4 * *p]; *q++ = col[0]; *q++ = col[1]; *q++ = col[2]; *q++ = col[3]; break; #endif } *aq++ = alpha; } else { switch (imgData->colorMode) { case splashModeMono1: case splashModeMono8: imgData->colorMap->getGray(p, &gray); *q++ = colToByte(gray); break; case splashModeRGB8: case splashModeBGR8: imgData->colorMap->getRGB(p, &rgb); *q++ = colToByte(rgb.r); *q++ = colToByte(rgb.g); *q++ = colToByte(rgb.b); break; #if SPLASH_CMYK case splashModeCMYK8: imgData->colorMap->getCMYK(p, &cmyk); *q++ = colToByte(cmyk.c); *q++ = colToByte(cmyk.m); *q++ = colToByte(cmyk.y); *q++ = colToByte(cmyk.k); break; #endif } *aq++ = alpha; } } ++imgData->y; return gTrue; } void SplashOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { GfxImageColorMap *maskColorMap; Object maskDecode, decodeLow, decodeHigh; double *ctm; SplashCoord mat[6]; SplashOutMaskedImageData imgData; SplashOutImageMaskData imgMaskData; SplashColorMode srcMode; SplashBitmap *maskBitmap; Splash *maskSplash; SplashColor maskColor; GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif Guchar pix; int n, i; setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), NULL); // If the mask is higher resolution than the image, use // drawSoftMaskedImage() instead. if (maskWidth > width || maskHeight > height) { decodeLow.initInt(maskInvert ? 0 : 1); decodeHigh.initInt(maskInvert ? 1 : 0); maskDecode.initArray(xref); maskDecode.arrayAdd(&decodeLow); maskDecode.arrayAdd(&decodeHigh); maskColorMap = new GfxImageColorMap(1, &maskDecode, new GfxDeviceGrayColorSpace()); maskDecode.free(); drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); delete maskColorMap; } else { //----- scale the mask image to the same size as the source image mat[0] = (SplashCoord)width; mat[1] = 0; mat[2] = 0; mat[3] = (SplashCoord)height; mat[4] = 0; mat[5] = 0; imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, 1, 1); imgMaskData.imgStr->reset(); imgMaskData.invert = maskInvert ? 0 : 1; imgMaskData.width = maskWidth; imgMaskData.height = maskHeight; imgMaskData.y = 0; maskBitmap = new SplashBitmap(width, height, 1, splashModeMono1, gFalse); maskSplash = new Splash(maskBitmap, gFalse); maskColor[0] = 0; maskSplash->clear(maskColor); maskColor[0] = 0xff; maskSplash->setFillPattern(new SplashSolidColor(maskColor)); maskSplash->fillImageMask(&imageMaskSrc, &imgMaskData, maskWidth, maskHeight, mat, gFalse); delete imgMaskData.imgStr; maskStr->close(); delete maskSplash; //----- draw the source image ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; mat[2] = -ctm[2]; mat[3] = -ctm[3]; mat[4] = ctm[2] + ctm[4]; mat[5] = ctm[3] + ctm[5]; imgData.imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgData.imgStr->reset(); imgData.colorMap = colorMap; imgData.mask = maskBitmap; imgData.colorMode = colorMode; imgData.width = width; imgData.height = height; imgData.y = 0; // special case for one-channel (monochrome/gray/separation) images: // build a lookup table here imgData.lookup = NULL; if (colorMap->getNumPixelComps() == 1) { n = 1 << colorMap->getBits(); switch (colorMode) { case splashModeMono1: case splashModeMono8: imgData.lookup = (SplashColorPtr)gmalloc(n); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getGray(&pix, &gray); imgData.lookup[i] = colToByte(gray); } break; case splashModeRGB8: case splashModeBGR8: imgData.lookup = (SplashColorPtr)gmallocn(n, 3); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getRGB(&pix, &rgb); imgData.lookup[3*i] = colToByte(rgb.r); imgData.lookup[3*i+1] = colToByte(rgb.g); imgData.lookup[3*i+2] = colToByte(rgb.b); } break; #if SPLASH_CMYK case splashModeCMYK8: imgData.lookup = (SplashColorPtr)gmallocn(n, 4); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getCMYK(&pix, &cmyk); imgData.lookup[4*i] = colToByte(cmyk.c); imgData.lookup[4*i+1] = colToByte(cmyk.m); imgData.lookup[4*i+2] = colToByte(cmyk.y); imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; #endif } } if (colorMode == splashModeMono1) { srcMode = splashModeMono8; } else { srcMode = colorMode; } splash->drawImage(&maskedImageSrc, &imgData, srcMode, gTrue, width, height, mat); delete maskBitmap; gfree(imgData.lookup); delete imgData.imgStr; str->close(); } } void SplashOutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap) { double *ctm; SplashCoord mat[6]; SplashOutImageData imgData; SplashOutImageData imgMaskData; SplashColorMode srcMode; SplashBitmap *maskBitmap; Splash *maskSplash; SplashColor maskColor; GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif Guchar pix; int n, i; setOverprintMask(colorMap->getColorSpace(), state->getFillOverprint(), state->getOverprintMode(), NULL); ctm = state->getCTM(); mat[0] = ctm[0]; mat[1] = ctm[1]; mat[2] = -ctm[2]; mat[3] = -ctm[3]; mat[4] = ctm[2] + ctm[4]; mat[5] = ctm[3] + ctm[5]; //----- set up the soft mask imgMaskData.imgStr = new ImageStream(maskStr, maskWidth, maskColorMap->getNumPixelComps(), maskColorMap->getBits()); imgMaskData.imgStr->reset(); imgMaskData.colorMap = maskColorMap; imgMaskData.maskColors = NULL; imgMaskData.colorMode = splashModeMono8; imgMaskData.width = maskWidth; imgMaskData.height = maskHeight; imgMaskData.y = 0; n = 1 << maskColorMap->getBits(); imgMaskData.lookup = (SplashColorPtr)gmalloc(n); for (i = 0; i < n; ++i) { pix = (Guchar)i; maskColorMap->getGray(&pix, &gray); imgMaskData.lookup[i] = colToByte(gray); } maskBitmap = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse); maskSplash = new Splash(maskBitmap, vectorAntialias); maskColor[0] = 0; maskSplash->clear(maskColor); maskSplash->drawImage(&imageSrc, &imgMaskData, splashModeMono8, gFalse, maskWidth, maskHeight, mat); delete imgMaskData.imgStr; maskStr->close(); gfree(imgMaskData.lookup); delete maskSplash; splash->setSoftMask(maskBitmap); //----- draw the source image imgData.imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgData.imgStr->reset(); imgData.colorMap = colorMap; imgData.maskColors = NULL; imgData.colorMode = colorMode; imgData.width = width; imgData.height = height; imgData.y = 0; // special case for one-channel (monochrome/gray/separation) images: // build a lookup table here imgData.lookup = NULL; if (colorMap->getNumPixelComps() == 1) { n = 1 << colorMap->getBits(); switch (colorMode) { case splashModeMono1: case splashModeMono8: imgData.lookup = (SplashColorPtr)gmalloc(n); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getGray(&pix, &gray); imgData.lookup[i] = colToByte(gray); } break; case splashModeRGB8: case splashModeBGR8: imgData.lookup = (SplashColorPtr)gmallocn(n, 3); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getRGB(&pix, &rgb); imgData.lookup[3*i] = colToByte(rgb.r); imgData.lookup[3*i+1] = colToByte(rgb.g); imgData.lookup[3*i+2] = colToByte(rgb.b); } break; #if SPLASH_CMYK case splashModeCMYK8: imgData.lookup = (SplashColorPtr)gmallocn(n, 4); for (i = 0; i < n; ++i) { pix = (Guchar)i; colorMap->getCMYK(&pix, &cmyk); imgData.lookup[4*i] = colToByte(cmyk.c); imgData.lookup[4*i+1] = colToByte(cmyk.m); imgData.lookup[4*i+2] = colToByte(cmyk.y); imgData.lookup[4*i+3] = colToByte(cmyk.k); } break; #endif } } if (colorMode == splashModeMono1) { srcMode = splashModeMono8; } else { srcMode = colorMode; } splash->drawImage(&imageSrc, &imgData, srcMode, gFalse, width, height, mat); splash->setSoftMask(NULL); gfree(imgData.lookup); delete imgData.imgStr; str->close(); } void SplashOutputDev::beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask) { SplashTransparencyGroup *transpGroup; SplashColor color; double xMin, yMin, xMax, yMax, x, y; int tx, ty, w, h, i; // transform the bbox state->transform(bbox[0], bbox[1], &x, &y); xMin = xMax = x; yMin = yMax = y; state->transform(bbox[0], bbox[3], &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } state->transform(bbox[2], bbox[1], &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } state->transform(bbox[2], bbox[3], &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } tx = (int)floor(xMin); if (tx < 0) { tx = 0; } else if (tx >= bitmap->getWidth()) { tx = bitmap->getWidth() - 1; } ty = (int)floor(yMin); if (ty < 0) { ty = 0; } else if (ty >= bitmap->getHeight()) { ty = bitmap->getHeight() - 1; } w = (int)ceil(xMax) - tx + 1; if (tx + w > bitmap->getWidth()) { w = bitmap->getWidth() - tx; } if (w < 1) { w = 1; } h = (int)ceil(yMax) - ty + 1; if (ty + h > bitmap->getHeight()) { h = bitmap->getHeight() - ty; } if (h < 1) { h = 1; } // push a new stack entry transpGroup = new SplashTransparencyGroup(); transpGroup->tx = tx; transpGroup->ty = ty; transpGroup->blendingColorSpace = blendingColorSpace; transpGroup->isolated = isolated; transpGroup->next = transpGroupStack; transpGroupStack = transpGroup; // save state transpGroup->origBitmap = bitmap; transpGroup->origSplash = splash; //~ this handles the blendingColorSpace arg for soft masks, but //~ not yet for transparency groups // switch to the blending color space if (forSoftMask && isolated && blendingColorSpace) { if (blendingColorSpace->getMode() == csDeviceGray || blendingColorSpace->getMode() == csCalGray || (blendingColorSpace->getMode() == csICCBased && blendingColorSpace->getNComps() == 1)) { colorMode = splashModeMono8; } else if (blendingColorSpace->getMode() == csDeviceRGB || blendingColorSpace->getMode() == csCalRGB || (blendingColorSpace->getMode() == csICCBased && blendingColorSpace->getNComps() == 3)) { //~ does this need to use BGR8? colorMode = splashModeRGB8; #if SPLASH_CMYK } else if (blendingColorSpace->getMode() == csDeviceCMYK || (blendingColorSpace->getMode() == csICCBased && blendingColorSpace->getNComps() == 4)) { colorMode = splashModeCMYK8; #endif } } // create the temporary bitmap bitmap = new SplashBitmap(w, h, bitmapRowPad, colorMode, gTrue, bitmapTopDown); splash = new Splash(bitmap, vectorAntialias, transpGroup->origSplash->getScreen()); splash->setMinLineWidth(globalParams->getMinLineWidth()); //~ Acrobat apparently copies at least the fill and stroke colors, and //~ maybe other state(?) -- but not the clipping path (and not sure //~ what else) //~ [this is likely the same situation as in type3D1()] splash->setFillPattern(transpGroup->origSplash->getFillPattern()->copy()); splash->setStrokePattern( transpGroup->origSplash->getStrokePattern()->copy()); if (isolated) { for (i = 0; i < splashMaxColorComps; ++i) { color[i] = 0; } splash->clear(color, 0); } else { splash->blitTransparent(transpGroup->origBitmap, tx, ty, 0, 0, w, h); splash->setInNonIsolatedGroup(transpGroup->origBitmap, tx, ty); } transpGroup->tBitmap = bitmap; state->shiftCTM(-tx, -ty); updateCTM(state, 0, 0, 0, 0, 0, 0); ++nestCount; } void SplashOutputDev::endTransparencyGroup(GfxState *state) { // restore state --nestCount; delete splash; bitmap = transpGroupStack->origBitmap; colorMode = bitmap->getMode(); splash = transpGroupStack->origSplash; state->shiftCTM(transpGroupStack->tx, transpGroupStack->ty); updateCTM(state, 0, 0, 0, 0, 0, 0); } void SplashOutputDev::paintTransparencyGroup(GfxState *state, double *bbox) { SplashBitmap *tBitmap; SplashTransparencyGroup *transpGroup; GBool isolated; int tx, ty; tx = transpGroupStack->tx; ty = transpGroupStack->ty; tBitmap = transpGroupStack->tBitmap; isolated = transpGroupStack->isolated; // paint the transparency group onto the parent bitmap // - the clip path was set in the parent's state) if (tx < bitmap->getWidth() && ty < bitmap->getHeight()) { splash->setOverprintMask(0xffffffff); splash->composite(tBitmap, 0, 0, tx, ty, tBitmap->getWidth(), tBitmap->getHeight(), gFalse, !isolated); } // pop the stack transpGroup = transpGroupStack; transpGroupStack = transpGroup->next; delete transpGroup; delete tBitmap; } void SplashOutputDev::setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor) { SplashBitmap *softMask, *tBitmap; Splash *tSplash; SplashTransparencyGroup *transpGroup; SplashColor color; SplashColorPtr p; GfxGray gray; GfxRGB rgb; #if SPLASH_CMYK GfxCMYK cmyk; #endif double lum, lum2; int tx, ty, x, y; tx = transpGroupStack->tx; ty = transpGroupStack->ty; tBitmap = transpGroupStack->tBitmap; // composite with backdrop color if (!alpha && tBitmap->getMode() != splashModeMono1) { //~ need to correctly handle the case where no blending color //~ space is given tSplash = new Splash(tBitmap, vectorAntialias, transpGroupStack->origSplash->getScreen()); if (transpGroupStack->blendingColorSpace) { switch (tBitmap->getMode()) { case splashModeMono1: // transparency is not supported in mono1 mode break; case splashModeMono8: transpGroupStack->blendingColorSpace->getGray(backdropColor, &gray); color[0] = colToByte(gray); tSplash->compositeBackground(color); break; case splashModeRGB8: case splashModeBGR8: transpGroupStack->blendingColorSpace->getRGB(backdropColor, &rgb); color[0] = colToByte(rgb.r); color[1] = colToByte(rgb.g); color[2] = colToByte(rgb.b); tSplash->compositeBackground(color); break; #if SPLASH_CMYK case splashModeCMYK8: transpGroupStack->blendingColorSpace->getCMYK(backdropColor, &cmyk); color[0] = colToByte(cmyk.c); color[1] = colToByte(cmyk.m); color[2] = colToByte(cmyk.y); color[3] = colToByte(cmyk.k); tSplash->compositeBackground(color); break; #endif } delete tSplash; } } softMask = new SplashBitmap(bitmap->getWidth(), bitmap->getHeight(), 1, splashModeMono8, gFalse); memset(softMask->getDataPtr(), 0, softMask->getRowSize() * softMask->getHeight()); if (tx < softMask->getWidth() && ty < softMask->getHeight()) { p = softMask->getDataPtr() + ty * softMask->getRowSize() + tx; for (y = 0; y < tBitmap->getHeight(); ++y) { for (x = 0; x < tBitmap->getWidth(); ++x) { if (alpha) { lum = tBitmap->getAlpha(x, y) / 255.0; } else { tBitmap->getPixel(x, y, color); // convert to luminosity switch (tBitmap->getMode()) { case splashModeMono1: case splashModeMono8: lum = color[0] / 255.0; break; case splashModeRGB8: case splashModeBGR8: lum = (0.3 / 255.0) * color[0] + (0.59 / 255.0) * color[1] + (0.11 / 255.0) * color[2]; break; #if SPLASH_CMYK case splashModeCMYK8: lum = (1 - color[3] / 255.0) - (0.3 / 255.0) * color[0] - (0.59 / 255.0) * color[1] - (0.11 / 255.0) * color[2]; if (lum < 0) { lum = 0; } break; #endif } } if (transferFunc) { transferFunc->transform(&lum, &lum2); } else { lum2 = lum; } p[x] = (int)(lum2 * 255.0 + 0.5); } p += softMask->getRowSize(); } } splash->setSoftMask(softMask); // pop the stack transpGroup = transpGroupStack; transpGroupStack = transpGroup->next; delete transpGroup; delete tBitmap; } void SplashOutputDev::clearSoftMask(GfxState *state) { splash->setSoftMask(NULL); } void SplashOutputDev::setPaperColor(SplashColorPtr paperColorA) { splashColorCopy(paperColor, paperColorA); } int SplashOutputDev::getBitmapWidth() { return bitmap->getWidth(); } int SplashOutputDev::getBitmapHeight() { return bitmap->getHeight(); } SplashBitmap *SplashOutputDev::takeBitmap() { SplashBitmap *ret; ret = bitmap; bitmap = new SplashBitmap(1, 1, bitmapRowPad, colorMode, colorMode != splashModeMono1, bitmapTopDown); return ret; } void SplashOutputDev::getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) { splash->getModRegion(xMin, yMin, xMax, yMax); } void SplashOutputDev::clearModRegion() { splash->clearModRegion(); } void SplashOutputDev::setFillColor(int r, int g, int b) { GfxRGB rgb; GfxGray gray; #if SPLASH_CMYK GfxCMYK cmyk; #endif rgb.r = byteToCol(r); rgb.g = byteToCol(g); rgb.b = byteToCol(b); switch (colorMode) { case splashModeMono1: case splashModeMono8: gray = (GfxColorComp)(0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.g + 0.5); if (gray > gfxColorComp1) { gray = gfxColorComp1; } splash->setFillPattern(getColor(gray)); break; case splashModeRGB8: case splashModeBGR8: splash->setFillPattern(getColor(&rgb)); break; #if SPLASH_CMYK case splashModeCMYK8: cmyk.c = gfxColorComp1 - rgb.r; cmyk.m = gfxColorComp1 - rgb.g; cmyk.y = gfxColorComp1 - rgb.b; cmyk.k = 0; splash->setFillPattern(getColor(&cmyk)); break; #endif } } SplashFont *SplashOutputDev::getFont(GString *name, SplashCoord *textMatA) { Ref ref; SplashOutFontFileID *id; GfxFontLoc *fontLoc; SplashFontFile *fontFile; SplashFont *fontObj; FoFiTrueType *ff; int *codeToGID; Unicode u; SplashCoord textMat[4]; int cmap, i; for (i = 0; i < nBuiltinFonts; ++i) { if (!name->cmp(builtinFonts[i].name)) { break; } } if (i == nBuiltinFonts) { return NULL; } ref.num = i; ref.gen = -1; id = new SplashOutFontFileID(&ref); // check the font file cache if ((fontFile = fontEngine->getFontFile(id))) { delete id; // load the font file } else { if (!(fontLoc = GfxFont::locateBase14Font(name))) { return NULL; } if (fontLoc->fontType == fontType1) { fontFile = fontEngine->loadType1Font(id, fontLoc->path->getCString(), gFalse, winAnsiEncoding); } else if (fontLoc->fontType == fontTrueType) { if (!(ff = FoFiTrueType::load(fontLoc->path->getCString()))) { delete fontLoc; delete id; return NULL; } for (cmap = 0; cmap < ff->getNumCmaps(); ++cmap) { if ((ff->getCmapPlatform(cmap) == 3 && ff->getCmapEncoding(cmap) == 1) || ff->getCmapPlatform(cmap) == 0) { break; } } if (cmap == ff->getNumCmaps()) { delete ff; delete fontLoc; delete id; return NULL; } codeToGID = (int *)gmallocn(256, sizeof(int)); for (i = 0; i < 256; ++i) { codeToGID[i] = 0; if (winAnsiEncoding[i] && (u = globalParams->mapNameToUnicode(winAnsiEncoding[i]))) { codeToGID[i] = ff->mapCodeToGID(cmap, u); } } delete ff; fontFile = fontEngine->loadTrueTypeFont(id, fontLoc->path->getCString(), fontLoc->fontNum, gFalse, codeToGID, 256, NULL); } else { delete fontLoc; delete id; return NULL; } delete fontLoc; } if (!fontFile) { return NULL; } // create the scaled font textMat[0] = (SplashCoord)textMatA[0]; textMat[1] = (SplashCoord)textMatA[1]; textMat[2] = (SplashCoord)textMatA[2]; textMat[3] = (SplashCoord)textMatA[3]; fontObj = fontEngine->getFont(fontFile, textMat, splash->getMatrix()); return fontObj; } #if 1 //~tmp: turn off anti-aliasing temporarily void SplashOutputDev::setInShading(GBool sh) { splash->setInShading(sh); } #endif xpdf-3.03/xpdf/PSTokenizer.h0000644000076400007640000000140311622305345015240 0ustar dereknderekn//======================================================================== // // PSTokenizer.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef PSTOKENIZER_H #define PSTOKENIZER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" //------------------------------------------------------------------------ class PSTokenizer { public: PSTokenizer(int (*getCharFuncA)(void *), void *dataA); ~PSTokenizer(); // Get the next PostScript token. Returns false at end-of-stream. GBool getToken(char *buf, int size, int *length); private: int lookChar(); int getChar(); int (*getCharFunc)(void *); void *data; int charBuf; }; #endif xpdf-3.03/xpdf/UnicodeTypeTable.cc0000644000076400007640000011635711622305345016400 0ustar dereknderekn//======================================================================== // // UnicodeTypeTable.cc // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include #include "CharTypes.h" #include "UnicodeTypeTable.h" struct UnicodeMapTableEntry { const char *vector; char type; }; struct UnicodeCaseTableVector { Unicode codes[256]; }; static UnicodeMapTableEntry typeTable[256] = { { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN###NNNNN################NNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#N####NNNNLNNNNN####NLNNN#LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLL", 'X' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLNNNNNNNNNNNNNNLLNNNNNNNNNNNNNNLLLLLNNNNNNNNNLNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLNNNNNNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNRNRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, { "RRRR#########RNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNN####################RRRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNRNNNNNNNRRNNNNNNNRR##########RRRRRR", 'X' }, { "RRRRRRRRRRRRRRNNRNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNNNNNNNNNNNNNNNNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNNNNNNNNNNRNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'N' }, { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLNNNNLLLLLLLLLLLLLNNLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNLLLLLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLL##LLLLLLLNNNNN", 'X' }, { "NNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLNNNNNNNNLLLLNLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLL##NNNNNNNNNNNNNN", 'X' }, { "NNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLNLNNNLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNN#NLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNN#####LLLLLLLNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLNNNNNNNNNLLLLLLLLLLNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNLNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNLNNNNNLNNLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLNNNNNNLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNLLLLLLLLNLLNNNNNNNNNNNLLLLLLL#LNLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLNNNNNLLLLLLNLLLLLLNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLNNNLLLLLLLLLLLNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLNNNLLLLLLLLLLLLLNNN", 'X' }, { "NNNNNNNNNNNNNNLRNNNNNNNNNNNNNNNNNNNNNNNNNNLRNLRN#####NNNNNNNNNNNNNNN#NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#L##########NNNL############NNN###################################NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNLNNNNLNNLLLLLLLLLLNLNNNLLLLLNNNNNNLNLNLNLLLL#LLLNLLLLLLLNNLLLLNNNNNLLLLLNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNNNN##NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN####################LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'L' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { NULL, 'N' }, { "NNNNNLLLNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLNNNNNNNLLLLLNNLLLLLNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNLLLL", 'X' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL", 'X' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { NULL, 'L' }, { "LLLLLLLLLLLLLLLLLLLLLLLLRRRRRRNRRRRRRRRRR#RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR", 'X' }, { NULL, 'R' }, { "RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, { "NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN#N#NN#NNNNNNNNN#NN##NNNNN##NRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRNNN", 'X' }, { "NNN###NNNNN################NNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL#####NNN##NNNNNNNNNNNNNNNNNNNNNNNLL", 'X' } }; static UnicodeCaseTableVector caseTable00 = {{ 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, 0x0018, 0x0019, 0x001a, 0x001b, 0x001c, 0x001d, 0x001e, 0x001f, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x007f, 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, 0x0088, 0x0089, 0x008a, 0x008b, 0x008c, 0x008d, 0x008e, 0x008f, 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, 0x0098, 0x0099, 0x009a, 0x009b, 0x009c, 0x009d, 0x009e, 0x009f, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x03bc, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00d7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }}; static UnicodeCaseTableVector caseTable01 = {{ 0x0101, 0x0101, 0x0103, 0x0103, 0x0105, 0x0105, 0x0107, 0x0107, 0x0109, 0x0109, 0x010b, 0x010b, 0x010d, 0x010d, 0x010f, 0x010f, 0x0111, 0x0111, 0x0113, 0x0113, 0x0115, 0x0115, 0x0117, 0x0117, 0x0119, 0x0119, 0x011b, 0x011b, 0x011d, 0x011d, 0x011f, 0x011f, 0x0121, 0x0121, 0x0123, 0x0123, 0x0125, 0x0125, 0x0127, 0x0127, 0x0129, 0x0129, 0x012b, 0x012b, 0x012d, 0x012d, 0x012f, 0x012f, 0x0130, 0x0131, 0x0133, 0x0133, 0x0135, 0x0135, 0x0137, 0x0137, 0x0138, 0x013a, 0x013a, 0x013c, 0x013c, 0x013e, 0x013e, 0x0140, 0x0140, 0x0142, 0x0142, 0x0144, 0x0144, 0x0146, 0x0146, 0x0148, 0x0148, 0x0149, 0x014b, 0x014b, 0x014d, 0x014d, 0x014f, 0x014f, 0x0151, 0x0151, 0x0153, 0x0153, 0x0155, 0x0155, 0x0157, 0x0157, 0x0159, 0x0159, 0x015b, 0x015b, 0x015d, 0x015d, 0x015f, 0x015f, 0x0161, 0x0161, 0x0163, 0x0163, 0x0165, 0x0165, 0x0167, 0x0167, 0x0169, 0x0169, 0x016b, 0x016b, 0x016d, 0x016d, 0x016f, 0x016f, 0x0171, 0x0171, 0x0173, 0x0173, 0x0175, 0x0175, 0x0177, 0x0177, 0x00ff, 0x017a, 0x017a, 0x017c, 0x017c, 0x017e, 0x017e, 0x0073, 0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188, 0x0188, 0x0256, 0x0257, 0x018c, 0x018c, 0x018d, 0x01dd, 0x0259, 0x025b, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268, 0x0199, 0x0199, 0x019a, 0x019b, 0x026f, 0x0272, 0x019e, 0x0275, 0x01a1, 0x01a1, 0x01a3, 0x01a3, 0x01a5, 0x01a5, 0x0280, 0x01a8, 0x01a8, 0x0283, 0x01aa, 0x01ab, 0x01ad, 0x01ad, 0x0288, 0x01b0, 0x01b0, 0x028a, 0x028b, 0x01b4, 0x01b4, 0x01b6, 0x01b6, 0x0292, 0x01b9, 0x01b9, 0x01ba, 0x01bb, 0x01bd, 0x01bd, 0x01be, 0x01bf, 0x01c0, 0x01c1, 0x01c2, 0x01c3, 0x01c6, 0x01c6, 0x01c6, 0x01c9, 0x01c9, 0x01c9, 0x01cc, 0x01cc, 0x01cc, 0x01ce, 0x01ce, 0x01d0, 0x01d0, 0x01d2, 0x01d2, 0x01d4, 0x01d4, 0x01d6, 0x01d6, 0x01d8, 0x01d8, 0x01da, 0x01da, 0x01dc, 0x01dc, 0x01dd, 0x01df, 0x01df, 0x01e1, 0x01e1, 0x01e3, 0x01e3, 0x01e5, 0x01e5, 0x01e7, 0x01e7, 0x01e9, 0x01e9, 0x01eb, 0x01eb, 0x01ed, 0x01ed, 0x01ef, 0x01ef, 0x01f0, 0x01f3, 0x01f3, 0x01f3, 0x01f5, 0x01f5, 0x0195, 0x01bf, 0x01f9, 0x01f9, 0x01fb, 0x01fb, 0x01fd, 0x01fd, 0x01ff, 0x01ff }}; static UnicodeCaseTableVector caseTable02 = {{ 0x0201, 0x0201, 0x0203, 0x0203, 0x0205, 0x0205, 0x0207, 0x0207, 0x0209, 0x0209, 0x020b, 0x020b, 0x020d, 0x020d, 0x020f, 0x020f, 0x0211, 0x0211, 0x0213, 0x0213, 0x0215, 0x0215, 0x0217, 0x0217, 0x0219, 0x0219, 0x021b, 0x021b, 0x021d, 0x021d, 0x021f, 0x021f, 0x019e, 0x0221, 0x0223, 0x0223, 0x0225, 0x0225, 0x0227, 0x0227, 0x0229, 0x0229, 0x022b, 0x022b, 0x022d, 0x022d, 0x022f, 0x022f, 0x0231, 0x0231, 0x0233, 0x0233, 0x0234, 0x0235, 0x0236, 0x0237, 0x0238, 0x0239, 0x023a, 0x023b, 0x023c, 0x023d, 0x023e, 0x023f, 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0245, 0x0246, 0x0247, 0x0248, 0x0249, 0x024a, 0x024b, 0x024c, 0x024d, 0x024e, 0x024f, 0x0250, 0x0251, 0x0252, 0x0253, 0x0254, 0x0255, 0x0256, 0x0257, 0x0258, 0x0259, 0x025a, 0x025b, 0x025c, 0x025d, 0x025e, 0x025f, 0x0260, 0x0261, 0x0262, 0x0263, 0x0264, 0x0265, 0x0266, 0x0267, 0x0268, 0x0269, 0x026a, 0x026b, 0x026c, 0x026d, 0x026e, 0x026f, 0x0270, 0x0271, 0x0272, 0x0273, 0x0274, 0x0275, 0x0276, 0x0277, 0x0278, 0x0279, 0x027a, 0x027b, 0x027c, 0x027d, 0x027e, 0x027f, 0x0280, 0x0281, 0x0282, 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, 0x0288, 0x0289, 0x028a, 0x028b, 0x028c, 0x028d, 0x028e, 0x028f, 0x0290, 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, 0x0296, 0x0297, 0x0298, 0x0299, 0x029a, 0x029b, 0x029c, 0x029d, 0x029e, 0x029f, 0x02a0, 0x02a1, 0x02a2, 0x02a3, 0x02a4, 0x02a5, 0x02a6, 0x02a7, 0x02a8, 0x02a9, 0x02aa, 0x02ab, 0x02ac, 0x02ad, 0x02ae, 0x02af, 0x02b0, 0x02b1, 0x02b2, 0x02b3, 0x02b4, 0x02b5, 0x02b6, 0x02b7, 0x02b8, 0x02b9, 0x02ba, 0x02bb, 0x02bc, 0x02bd, 0x02be, 0x02bf, 0x02c0, 0x02c1, 0x02c2, 0x02c3, 0x02c4, 0x02c5, 0x02c6, 0x02c7, 0x02c8, 0x02c9, 0x02ca, 0x02cb, 0x02cc, 0x02cd, 0x02ce, 0x02cf, 0x02d0, 0x02d1, 0x02d2, 0x02d3, 0x02d4, 0x02d5, 0x02d6, 0x02d7, 0x02d8, 0x02d9, 0x02da, 0x02db, 0x02dc, 0x02dd, 0x02de, 0x02df, 0x02e0, 0x02e1, 0x02e2, 0x02e3, 0x02e4, 0x02e5, 0x02e6, 0x02e7, 0x02e8, 0x02e9, 0x02ea, 0x02eb, 0x02ec, 0x02ed, 0x02ee, 0x02ef, 0x02f0, 0x02f1, 0x02f2, 0x02f3, 0x02f4, 0x02f5, 0x02f6, 0x02f7, 0x02f8, 0x02f9, 0x02fa, 0x02fb, 0x02fc, 0x02fd, 0x02fe, 0x02ff }}; static UnicodeCaseTableVector caseTable03 = {{ 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0305, 0x0306, 0x0307, 0x0308, 0x0309, 0x030a, 0x030b, 0x030c, 0x030d, 0x030e, 0x030f, 0x0310, 0x0311, 0x0312, 0x0313, 0x0314, 0x0315, 0x0316, 0x0317, 0x0318, 0x0319, 0x031a, 0x031b, 0x031c, 0x031d, 0x031e, 0x031f, 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0325, 0x0326, 0x0327, 0x0328, 0x0329, 0x032a, 0x032b, 0x032c, 0x032d, 0x032e, 0x032f, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0335, 0x0336, 0x0337, 0x0338, 0x0339, 0x033a, 0x033b, 0x033c, 0x033d, 0x033e, 0x033f, 0x0340, 0x0341, 0x0342, 0x0343, 0x0344, 0x03b9, 0x0346, 0x0347, 0x0348, 0x0349, 0x034a, 0x034b, 0x034c, 0x034d, 0x034e, 0x034f, 0x0350, 0x0351, 0x0352, 0x0353, 0x0354, 0x0355, 0x0356, 0x0357, 0x0358, 0x0359, 0x035a, 0x035b, 0x035c, 0x035d, 0x035e, 0x035f, 0x0360, 0x0361, 0x0362, 0x0363, 0x0364, 0x0365, 0x0366, 0x0367, 0x0368, 0x0369, 0x036a, 0x036b, 0x036c, 0x036d, 0x036e, 0x036f, 0x0370, 0x0371, 0x0372, 0x0373, 0x0374, 0x0375, 0x0376, 0x0377, 0x0378, 0x0379, 0x037a, 0x037b, 0x037c, 0x037d, 0x037e, 0x037f, 0x0380, 0x0381, 0x0382, 0x0383, 0x0384, 0x0385, 0x03ac, 0x0387, 0x03ad, 0x03ae, 0x03af, 0x038b, 0x03cc, 0x038d, 0x03cd, 0x03ce, 0x0390, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03a2, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03ac, 0x03ad, 0x03ae, 0x03af, 0x03b0, 0x03b1, 0x03b2, 0x03b3, 0x03b4, 0x03b5, 0x03b6, 0x03b7, 0x03b8, 0x03b9, 0x03ba, 0x03bb, 0x03bc, 0x03bd, 0x03be, 0x03bf, 0x03c0, 0x03c1, 0x03c3, 0x03c3, 0x03c4, 0x03c5, 0x03c6, 0x03c7, 0x03c8, 0x03c9, 0x03ca, 0x03cb, 0x03cc, 0x03cd, 0x03ce, 0x03cf, 0x03b2, 0x03b8, 0x03d2, 0x03d3, 0x03d4, 0x03c6, 0x03c0, 0x03d7, 0x03d9, 0x03d9, 0x03db, 0x03db, 0x03dd, 0x03dd, 0x03df, 0x03df, 0x03e1, 0x03e1, 0x03e3, 0x03e3, 0x03e5, 0x03e5, 0x03e7, 0x03e7, 0x03e9, 0x03e9, 0x03eb, 0x03eb, 0x03ed, 0x03ed, 0x03ef, 0x03ef, 0x03ba, 0x03c1, 0x03f2, 0x03f3, 0x03b8, 0x03b5, 0x03f6, 0x03f8, 0x03f8, 0x03f2, 0x03fb, 0x03fb, 0x03fc, 0x03fd, 0x03fe, 0x03ff }}; static UnicodeCaseTableVector caseTable04 = {{ 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, 0x0461, 0x0461, 0x0463, 0x0463, 0x0465, 0x0465, 0x0467, 0x0467, 0x0469, 0x0469, 0x046b, 0x046b, 0x046d, 0x046d, 0x046f, 0x046f, 0x0471, 0x0471, 0x0473, 0x0473, 0x0475, 0x0475, 0x0477, 0x0477, 0x0479, 0x0479, 0x047b, 0x047b, 0x047d, 0x047d, 0x047f, 0x047f, 0x0481, 0x0481, 0x0482, 0x0483, 0x0484, 0x0485, 0x0486, 0x0487, 0x0488, 0x0489, 0x048b, 0x048b, 0x048d, 0x048d, 0x048f, 0x048f, 0x0491, 0x0491, 0x0493, 0x0493, 0x0495, 0x0495, 0x0497, 0x0497, 0x0499, 0x0499, 0x049b, 0x049b, 0x049d, 0x049d, 0x049f, 0x049f, 0x04a1, 0x04a1, 0x04a3, 0x04a3, 0x04a5, 0x04a5, 0x04a7, 0x04a7, 0x04a9, 0x04a9, 0x04ab, 0x04ab, 0x04ad, 0x04ad, 0x04af, 0x04af, 0x04b1, 0x04b1, 0x04b3, 0x04b3, 0x04b5, 0x04b5, 0x04b7, 0x04b7, 0x04b9, 0x04b9, 0x04bb, 0x04bb, 0x04bd, 0x04bd, 0x04bf, 0x04bf, 0x04c0, 0x04c2, 0x04c2, 0x04c4, 0x04c4, 0x04c6, 0x04c6, 0x04c8, 0x04c8, 0x04ca, 0x04ca, 0x04cc, 0x04cc, 0x04ce, 0x04ce, 0x04cf, 0x04d1, 0x04d1, 0x04d3, 0x04d3, 0x04d5, 0x04d5, 0x04d7, 0x04d7, 0x04d9, 0x04d9, 0x04db, 0x04db, 0x04dd, 0x04dd, 0x04df, 0x04df, 0x04e1, 0x04e1, 0x04e3, 0x04e3, 0x04e5, 0x04e5, 0x04e7, 0x04e7, 0x04e9, 0x04e9, 0x04eb, 0x04eb, 0x04ed, 0x04ed, 0x04ef, 0x04ef, 0x04f1, 0x04f1, 0x04f3, 0x04f3, 0x04f5, 0x04f5, 0x04f6, 0x04f7, 0x04f9, 0x04f9, 0x04fa, 0x04fb, 0x04fc, 0x04fd, 0x04fe, 0x04ff }}; static UnicodeCaseTableVector caseTable05 = {{ 0x0501, 0x0501, 0x0503, 0x0503, 0x0505, 0x0505, 0x0507, 0x0507, 0x0509, 0x0509, 0x050b, 0x050b, 0x050d, 0x050d, 0x050f, 0x050f, 0x0510, 0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0516, 0x0517, 0x0518, 0x0519, 0x051a, 0x051b, 0x051c, 0x051d, 0x051e, 0x051f, 0x0520, 0x0521, 0x0522, 0x0523, 0x0524, 0x0525, 0x0526, 0x0527, 0x0528, 0x0529, 0x052a, 0x052b, 0x052c, 0x052d, 0x052e, 0x052f, 0x0530, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0557, 0x0558, 0x0559, 0x055a, 0x055b, 0x055c, 0x055d, 0x055e, 0x055f, 0x0560, 0x0561, 0x0562, 0x0563, 0x0564, 0x0565, 0x0566, 0x0567, 0x0568, 0x0569, 0x056a, 0x056b, 0x056c, 0x056d, 0x056e, 0x056f, 0x0570, 0x0571, 0x0572, 0x0573, 0x0574, 0x0575, 0x0576, 0x0577, 0x0578, 0x0579, 0x057a, 0x057b, 0x057c, 0x057d, 0x057e, 0x057f, 0x0580, 0x0581, 0x0582, 0x0583, 0x0584, 0x0585, 0x0586, 0x0587, 0x0588, 0x0589, 0x058a, 0x058b, 0x058c, 0x058d, 0x058e, 0x058f, 0x0590, 0x0591, 0x0592, 0x0593, 0x0594, 0x0595, 0x0596, 0x0597, 0x0598, 0x0599, 0x059a, 0x059b, 0x059c, 0x059d, 0x059e, 0x059f, 0x05a0, 0x05a1, 0x05a2, 0x05a3, 0x05a4, 0x05a5, 0x05a6, 0x05a7, 0x05a8, 0x05a9, 0x05aa, 0x05ab, 0x05ac, 0x05ad, 0x05ae, 0x05af, 0x05b0, 0x05b1, 0x05b2, 0x05b3, 0x05b4, 0x05b5, 0x05b6, 0x05b7, 0x05b8, 0x05b9, 0x05ba, 0x05bb, 0x05bc, 0x05bd, 0x05be, 0x05bf, 0x05c0, 0x05c1, 0x05c2, 0x05c3, 0x05c4, 0x05c5, 0x05c6, 0x05c7, 0x05c8, 0x05c9, 0x05ca, 0x05cb, 0x05cc, 0x05cd, 0x05ce, 0x05cf, 0x05d0, 0x05d1, 0x05d2, 0x05d3, 0x05d4, 0x05d5, 0x05d6, 0x05d7, 0x05d8, 0x05d9, 0x05da, 0x05db, 0x05dc, 0x05dd, 0x05de, 0x05df, 0x05e0, 0x05e1, 0x05e2, 0x05e3, 0x05e4, 0x05e5, 0x05e6, 0x05e7, 0x05e8, 0x05e9, 0x05ea, 0x05eb, 0x05ec, 0x05ed, 0x05ee, 0x05ef, 0x05f0, 0x05f1, 0x05f2, 0x05f3, 0x05f4, 0x05f5, 0x05f6, 0x05f7, 0x05f8, 0x05f9, 0x05fa, 0x05fb, 0x05fc, 0x05fd, 0x05fe, 0x05ff }}; static UnicodeCaseTableVector caseTable1e = {{ 0x1e01, 0x1e01, 0x1e03, 0x1e03, 0x1e05, 0x1e05, 0x1e07, 0x1e07, 0x1e09, 0x1e09, 0x1e0b, 0x1e0b, 0x1e0d, 0x1e0d, 0x1e0f, 0x1e0f, 0x1e11, 0x1e11, 0x1e13, 0x1e13, 0x1e15, 0x1e15, 0x1e17, 0x1e17, 0x1e19, 0x1e19, 0x1e1b, 0x1e1b, 0x1e1d, 0x1e1d, 0x1e1f, 0x1e1f, 0x1e21, 0x1e21, 0x1e23, 0x1e23, 0x1e25, 0x1e25, 0x1e27, 0x1e27, 0x1e29, 0x1e29, 0x1e2b, 0x1e2b, 0x1e2d, 0x1e2d, 0x1e2f, 0x1e2f, 0x1e31, 0x1e31, 0x1e33, 0x1e33, 0x1e35, 0x1e35, 0x1e37, 0x1e37, 0x1e39, 0x1e39, 0x1e3b, 0x1e3b, 0x1e3d, 0x1e3d, 0x1e3f, 0x1e3f, 0x1e41, 0x1e41, 0x1e43, 0x1e43, 0x1e45, 0x1e45, 0x1e47, 0x1e47, 0x1e49, 0x1e49, 0x1e4b, 0x1e4b, 0x1e4d, 0x1e4d, 0x1e4f, 0x1e4f, 0x1e51, 0x1e51, 0x1e53, 0x1e53, 0x1e55, 0x1e55, 0x1e57, 0x1e57, 0x1e59, 0x1e59, 0x1e5b, 0x1e5b, 0x1e5d, 0x1e5d, 0x1e5f, 0x1e5f, 0x1e61, 0x1e61, 0x1e63, 0x1e63, 0x1e65, 0x1e65, 0x1e67, 0x1e67, 0x1e69, 0x1e69, 0x1e6b, 0x1e6b, 0x1e6d, 0x1e6d, 0x1e6f, 0x1e6f, 0x1e71, 0x1e71, 0x1e73, 0x1e73, 0x1e75, 0x1e75, 0x1e77, 0x1e77, 0x1e79, 0x1e79, 0x1e7b, 0x1e7b, 0x1e7d, 0x1e7d, 0x1e7f, 0x1e7f, 0x1e81, 0x1e81, 0x1e83, 0x1e83, 0x1e85, 0x1e85, 0x1e87, 0x1e87, 0x1e89, 0x1e89, 0x1e8b, 0x1e8b, 0x1e8d, 0x1e8d, 0x1e8f, 0x1e8f, 0x1e91, 0x1e91, 0x1e93, 0x1e93, 0x1e95, 0x1e95, 0x1e96, 0x1e97, 0x1e98, 0x1e99, 0x1e9a, 0x1e61, 0x1e9c, 0x1e9d, 0x1e9e, 0x1e9f, 0x1ea1, 0x1ea1, 0x1ea3, 0x1ea3, 0x1ea5, 0x1ea5, 0x1ea7, 0x1ea7, 0x1ea9, 0x1ea9, 0x1eab, 0x1eab, 0x1ead, 0x1ead, 0x1eaf, 0x1eaf, 0x1eb1, 0x1eb1, 0x1eb3, 0x1eb3, 0x1eb5, 0x1eb5, 0x1eb7, 0x1eb7, 0x1eb9, 0x1eb9, 0x1ebb, 0x1ebb, 0x1ebd, 0x1ebd, 0x1ebf, 0x1ebf, 0x1ec1, 0x1ec1, 0x1ec3, 0x1ec3, 0x1ec5, 0x1ec5, 0x1ec7, 0x1ec7, 0x1ec9, 0x1ec9, 0x1ecb, 0x1ecb, 0x1ecd, 0x1ecd, 0x1ecf, 0x1ecf, 0x1ed1, 0x1ed1, 0x1ed3, 0x1ed3, 0x1ed5, 0x1ed5, 0x1ed7, 0x1ed7, 0x1ed9, 0x1ed9, 0x1edb, 0x1edb, 0x1edd, 0x1edd, 0x1edf, 0x1edf, 0x1ee1, 0x1ee1, 0x1ee3, 0x1ee3, 0x1ee5, 0x1ee5, 0x1ee7, 0x1ee7, 0x1ee9, 0x1ee9, 0x1eeb, 0x1eeb, 0x1eed, 0x1eed, 0x1eef, 0x1eef, 0x1ef1, 0x1ef1, 0x1ef3, 0x1ef3, 0x1ef5, 0x1ef5, 0x1ef7, 0x1ef7, 0x1ef9, 0x1ef9, 0x1efa, 0x1efb, 0x1efc, 0x1efd, 0x1efe, 0x1eff }}; static UnicodeCaseTableVector caseTable1f = {{ 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f16, 0x1f17, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x1f1e, 0x1f1f, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f20, 0x1f21, 0x1f22, 0x1f23, 0x1f24, 0x1f25, 0x1f26, 0x1f27, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, 0x1f30, 0x1f31, 0x1f32, 0x1f33, 0x1f34, 0x1f35, 0x1f36, 0x1f37, 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f46, 0x1f47, 0x1f40, 0x1f41, 0x1f42, 0x1f43, 0x1f44, 0x1f45, 0x1f4e, 0x1f4f, 0x1f50, 0x1f51, 0x1f52, 0x1f53, 0x1f54, 0x1f55, 0x1f56, 0x1f57, 0x1f58, 0x1f51, 0x1f5a, 0x1f53, 0x1f5c, 0x1f55, 0x1f5e, 0x1f57, 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f60, 0x1f61, 0x1f62, 0x1f63, 0x1f64, 0x1f65, 0x1f66, 0x1f67, 0x1f70, 0x1f71, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1f76, 0x1f77, 0x1f78, 0x1f79, 0x1f7a, 0x1f7b, 0x1f7c, 0x1f7d, 0x1f7e, 0x1f7f, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f80, 0x1f81, 0x1f82, 0x1f83, 0x1f84, 0x1f85, 0x1f86, 0x1f87, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1f90, 0x1f91, 0x1f92, 0x1f93, 0x1f94, 0x1f95, 0x1f96, 0x1f97, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fa0, 0x1fa1, 0x1fa2, 0x1fa3, 0x1fa4, 0x1fa5, 0x1fa6, 0x1fa7, 0x1fb0, 0x1fb1, 0x1fb2, 0x1fb3, 0x1fb4, 0x1fb5, 0x1fb6, 0x1fb7, 0x1fb0, 0x1fb1, 0x1f70, 0x1f71, 0x1fb3, 0x1fbd, 0x03b9, 0x1fbf, 0x1fc0, 0x1fc1, 0x1fc2, 0x1fc3, 0x1fc4, 0x1fc5, 0x1fc6, 0x1fc7, 0x1f72, 0x1f73, 0x1f74, 0x1f75, 0x1fc3, 0x1fcd, 0x1fce, 0x1fcf, 0x1fd0, 0x1fd1, 0x1fd2, 0x1fd3, 0x1fd4, 0x1fd5, 0x1fd6, 0x1fd7, 0x1fd0, 0x1fd1, 0x1f76, 0x1f77, 0x1fdc, 0x1fdd, 0x1fde, 0x1fdf, 0x1fe0, 0x1fe1, 0x1fe2, 0x1fe3, 0x1fe4, 0x1fe5, 0x1fe6, 0x1fe7, 0x1fe0, 0x1fe1, 0x1f7a, 0x1f7b, 0x1fe5, 0x1fed, 0x1fee, 0x1fef, 0x1ff0, 0x1ff1, 0x1ff2, 0x1ff3, 0x1ff4, 0x1ff5, 0x1ff6, 0x1ff7, 0x1f78, 0x1f79, 0x1f7c, 0x1f7d, 0x1ff3, 0x1ffd, 0x1ffe, 0x1fff }}; static UnicodeCaseTableVector caseTable21 = {{ 0x2100, 0x2101, 0x2102, 0x2103, 0x2104, 0x2105, 0x2106, 0x2107, 0x2108, 0x2109, 0x210a, 0x210b, 0x210c, 0x210d, 0x210e, 0x210f, 0x2110, 0x2111, 0x2112, 0x2113, 0x2114, 0x2115, 0x2116, 0x2117, 0x2118, 0x2119, 0x211a, 0x211b, 0x211c, 0x211d, 0x211e, 0x211f, 0x2120, 0x2121, 0x2122, 0x2123, 0x2124, 0x2125, 0x03c9, 0x2127, 0x2128, 0x2129, 0x006b, 0x00e5, 0x212c, 0x212d, 0x212e, 0x212f, 0x2130, 0x2131, 0x2132, 0x2133, 0x2134, 0x2135, 0x2136, 0x2137, 0x2138, 0x2139, 0x213a, 0x213b, 0x213c, 0x213d, 0x213e, 0x213f, 0x2140, 0x2141, 0x2142, 0x2143, 0x2144, 0x2145, 0x2146, 0x2147, 0x2148, 0x2149, 0x214a, 0x214b, 0x214c, 0x214d, 0x214e, 0x214f, 0x2150, 0x2151, 0x2152, 0x2153, 0x2154, 0x2155, 0x2156, 0x2157, 0x2158, 0x2159, 0x215a, 0x215b, 0x215c, 0x215d, 0x215e, 0x215f, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, 0x2170, 0x2171, 0x2172, 0x2173, 0x2174, 0x2175, 0x2176, 0x2177, 0x2178, 0x2179, 0x217a, 0x217b, 0x217c, 0x217d, 0x217e, 0x217f, 0x2180, 0x2181, 0x2182, 0x2183, 0x2184, 0x2185, 0x2186, 0x2187, 0x2188, 0x2189, 0x218a, 0x218b, 0x218c, 0x218d, 0x218e, 0x218f, 0x2190, 0x2191, 0x2192, 0x2193, 0x2194, 0x2195, 0x2196, 0x2197, 0x2198, 0x2199, 0x219a, 0x219b, 0x219c, 0x219d, 0x219e, 0x219f, 0x21a0, 0x21a1, 0x21a2, 0x21a3, 0x21a4, 0x21a5, 0x21a6, 0x21a7, 0x21a8, 0x21a9, 0x21aa, 0x21ab, 0x21ac, 0x21ad, 0x21ae, 0x21af, 0x21b0, 0x21b1, 0x21b2, 0x21b3, 0x21b4, 0x21b5, 0x21b6, 0x21b7, 0x21b8, 0x21b9, 0x21ba, 0x21bb, 0x21bc, 0x21bd, 0x21be, 0x21bf, 0x21c0, 0x21c1, 0x21c2, 0x21c3, 0x21c4, 0x21c5, 0x21c6, 0x21c7, 0x21c8, 0x21c9, 0x21ca, 0x21cb, 0x21cc, 0x21cd, 0x21ce, 0x21cf, 0x21d0, 0x21d1, 0x21d2, 0x21d3, 0x21d4, 0x21d5, 0x21d6, 0x21d7, 0x21d8, 0x21d9, 0x21da, 0x21db, 0x21dc, 0x21dd, 0x21de, 0x21df, 0x21e0, 0x21e1, 0x21e2, 0x21e3, 0x21e4, 0x21e5, 0x21e6, 0x21e7, 0x21e8, 0x21e9, 0x21ea, 0x21eb, 0x21ec, 0x21ed, 0x21ee, 0x21ef, 0x21f0, 0x21f1, 0x21f2, 0x21f3, 0x21f4, 0x21f5, 0x21f6, 0x21f7, 0x21f8, 0x21f9, 0x21fa, 0x21fb, 0x21fc, 0x21fd, 0x21fe, 0x21ff }}; static UnicodeCaseTableVector caseTable24 = {{ 0x2400, 0x2401, 0x2402, 0x2403, 0x2404, 0x2405, 0x2406, 0x2407, 0x2408, 0x2409, 0x240a, 0x240b, 0x240c, 0x240d, 0x240e, 0x240f, 0x2410, 0x2411, 0x2412, 0x2413, 0x2414, 0x2415, 0x2416, 0x2417, 0x2418, 0x2419, 0x241a, 0x241b, 0x241c, 0x241d, 0x241e, 0x241f, 0x2420, 0x2421, 0x2422, 0x2423, 0x2424, 0x2425, 0x2426, 0x2427, 0x2428, 0x2429, 0x242a, 0x242b, 0x242c, 0x242d, 0x242e, 0x242f, 0x2430, 0x2431, 0x2432, 0x2433, 0x2434, 0x2435, 0x2436, 0x2437, 0x2438, 0x2439, 0x243a, 0x243b, 0x243c, 0x243d, 0x243e, 0x243f, 0x2440, 0x2441, 0x2442, 0x2443, 0x2444, 0x2445, 0x2446, 0x2447, 0x2448, 0x2449, 0x244a, 0x244b, 0x244c, 0x244d, 0x244e, 0x244f, 0x2450, 0x2451, 0x2452, 0x2453, 0x2454, 0x2455, 0x2456, 0x2457, 0x2458, 0x2459, 0x245a, 0x245b, 0x245c, 0x245d, 0x245e, 0x245f, 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467, 0x2468, 0x2469, 0x246a, 0x246b, 0x246c, 0x246d, 0x246e, 0x246f, 0x2470, 0x2471, 0x2472, 0x2473, 0x2474, 0x2475, 0x2476, 0x2477, 0x2478, 0x2479, 0x247a, 0x247b, 0x247c, 0x247d, 0x247e, 0x247f, 0x2480, 0x2481, 0x2482, 0x2483, 0x2484, 0x2485, 0x2486, 0x2487, 0x2488, 0x2489, 0x248a, 0x248b, 0x248c, 0x248d, 0x248e, 0x248f, 0x2490, 0x2491, 0x2492, 0x2493, 0x2494, 0x2495, 0x2496, 0x2497, 0x2498, 0x2499, 0x249a, 0x249b, 0x249c, 0x249d, 0x249e, 0x249f, 0x24a0, 0x24a1, 0x24a2, 0x24a3, 0x24a4, 0x24a5, 0x24a6, 0x24a7, 0x24a8, 0x24a9, 0x24aa, 0x24ab, 0x24ac, 0x24ad, 0x24ae, 0x24af, 0x24b0, 0x24b1, 0x24b2, 0x24b3, 0x24b4, 0x24b5, 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, 0x24d0, 0x24d1, 0x24d2, 0x24d3, 0x24d4, 0x24d5, 0x24d6, 0x24d7, 0x24d8, 0x24d9, 0x24da, 0x24db, 0x24dc, 0x24dd, 0x24de, 0x24df, 0x24e0, 0x24e1, 0x24e2, 0x24e3, 0x24e4, 0x24e5, 0x24e6, 0x24e7, 0x24e8, 0x24e9, 0x24ea, 0x24eb, 0x24ec, 0x24ed, 0x24ee, 0x24ef, 0x24f0, 0x24f1, 0x24f2, 0x24f3, 0x24f4, 0x24f5, 0x24f6, 0x24f7, 0x24f8, 0x24f9, 0x24fa, 0x24fb, 0x24fc, 0x24fd, 0x24fe, 0x24ff }}; static UnicodeCaseTableVector caseTableff = {{ 0xff00, 0xff01, 0xff02, 0xff03, 0xff04, 0xff05, 0xff06, 0xff07, 0xff08, 0xff09, 0xff0a, 0xff0b, 0xff0c, 0xff0d, 0xff0e, 0xff0f, 0xff10, 0xff11, 0xff12, 0xff13, 0xff14, 0xff15, 0xff16, 0xff17, 0xff18, 0xff19, 0xff1a, 0xff1b, 0xff1c, 0xff1d, 0xff1e, 0xff1f, 0xff20, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0xff3b, 0xff3c, 0xff3d, 0xff3e, 0xff3f, 0xff40, 0xff41, 0xff42, 0xff43, 0xff44, 0xff45, 0xff46, 0xff47, 0xff48, 0xff49, 0xff4a, 0xff4b, 0xff4c, 0xff4d, 0xff4e, 0xff4f, 0xff50, 0xff51, 0xff52, 0xff53, 0xff54, 0xff55, 0xff56, 0xff57, 0xff58, 0xff59, 0xff5a, 0xff5b, 0xff5c, 0xff5d, 0xff5e, 0xff5f, 0xff60, 0xff61, 0xff62, 0xff63, 0xff64, 0xff65, 0xff66, 0xff67, 0xff68, 0xff69, 0xff6a, 0xff6b, 0xff6c, 0xff6d, 0xff6e, 0xff6f, 0xff70, 0xff71, 0xff72, 0xff73, 0xff74, 0xff75, 0xff76, 0xff77, 0xff78, 0xff79, 0xff7a, 0xff7b, 0xff7c, 0xff7d, 0xff7e, 0xff7f, 0xff80, 0xff81, 0xff82, 0xff83, 0xff84, 0xff85, 0xff86, 0xff87, 0xff88, 0xff89, 0xff8a, 0xff8b, 0xff8c, 0xff8d, 0xff8e, 0xff8f, 0xff90, 0xff91, 0xff92, 0xff93, 0xff94, 0xff95, 0xff96, 0xff97, 0xff98, 0xff99, 0xff9a, 0xff9b, 0xff9c, 0xff9d, 0xff9e, 0xff9f, 0xffa0, 0xffa1, 0xffa2, 0xffa3, 0xffa4, 0xffa5, 0xffa6, 0xffa7, 0xffa8, 0xffa9, 0xffaa, 0xffab, 0xffac, 0xffad, 0xffae, 0xffaf, 0xffb0, 0xffb1, 0xffb2, 0xffb3, 0xffb4, 0xffb5, 0xffb6, 0xffb7, 0xffb8, 0xffb9, 0xffba, 0xffbb, 0xffbc, 0xffbd, 0xffbe, 0xffbf, 0xffc0, 0xffc1, 0xffc2, 0xffc3, 0xffc4, 0xffc5, 0xffc6, 0xffc7, 0xffc8, 0xffc9, 0xffca, 0xffcb, 0xffcc, 0xffcd, 0xffce, 0xffcf, 0xffd0, 0xffd1, 0xffd2, 0xffd3, 0xffd4, 0xffd5, 0xffd6, 0xffd7, 0xffd8, 0xffd9, 0xffda, 0xffdb, 0xffdc, 0xffdd, 0xffde, 0xffdf, 0xffe0, 0xffe1, 0xffe2, 0xffe3, 0xffe4, 0xffe5, 0xffe6, 0xffe7, 0xffe8, 0xffe9, 0xffea, 0xffeb, 0xffec, 0xffed, 0xffee, 0xffef, 0xfff0, 0xfff1, 0xfff2, 0xfff3, 0xfff4, 0xfff5, 0xfff6, 0xfff7, 0xfff8, 0xfff9, 0xfffa, 0xfffb, 0xfffc, 0xfffd, 0xfffe, 0xffff }}; static UnicodeCaseTableVector *caseTable[256] = { &caseTable00, &caseTable01, &caseTable02, &caseTable03, &caseTable04, &caseTable05, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &caseTable1e, &caseTable1f, NULL, &caseTable21, NULL, NULL, &caseTable24, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &caseTableff }; static inline char getType(Unicode c) { int i; char type; if (c > 0xffff) { type = 'X'; } else { i = (c >> 8) & 0xff; if ((type = typeTable[i].type) == 'X') { type = typeTable[i].vector[c & 0xff]; } } return type; } GBool unicodeTypeL(Unicode c) { return getType(c) == 'L'; } GBool unicodeTypeR(Unicode c) { return getType(c) == 'R'; } GBool unicodeTypeNum(Unicode c) { return getType(c) == '#'; } GBool unicodeTypeAlphaNum(Unicode c) { char t; t = getType(c); return t == 'L' || t == 'R' || t == '#'; } Unicode unicodeToUpper(Unicode c) { int i; if (c > 0xffff) { return c; } i = (c >> 8) & 0xff; if (caseTable[i]) { return caseTable[i]->codes[c & 0xff]; } return c; } xpdf-3.03/xpdf/JBIG2Stream.h0000644000076400007640000001115111622305345014775 0ustar dereknderekn//======================================================================== // // JBIG2Stream.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef JBIG2STREAM_H #define JBIG2STREAM_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" #include "Stream.h" class GList; class JBIG2Segment; class JBIG2Bitmap; class JArithmeticDecoder; class JArithmeticDecoderStats; class JBIG2HuffmanDecoder; struct JBIG2HuffmanTable; class JBIG2MMRDecoder; //------------------------------------------------------------------------ class JBIG2Stream: public FilterStream { public: JBIG2Stream(Stream *strA, Object *globalsStreamA); virtual ~JBIG2Stream(); virtual StreamKind getKind() { return strJBIG2; } virtual void reset(); virtual void close(); virtual int getChar(); virtual int lookChar(); virtual int getBlock(char *blk, int size); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: void readSegments(); GBool readSymbolDictSeg(Guint segNum, Guint length, Guint *refSegs, Guint nRefSegs); void readTextRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs); JBIG2Bitmap *readTextRegion(GBool huff, GBool refine, int w, int h, Guint numInstances, Guint logStrips, int numSyms, JBIG2HuffmanTable *symCodeTab, Guint symCodeLen, JBIG2Bitmap **syms, Guint defPixel, Guint combOp, Guint transposed, Guint refCorner, int sOffset, JBIG2HuffmanTable *huffFSTable, JBIG2HuffmanTable *huffDSTable, JBIG2HuffmanTable *huffDTTable, JBIG2HuffmanTable *huffRDWTable, JBIG2HuffmanTable *huffRDHTable, JBIG2HuffmanTable *huffRDXTable, JBIG2HuffmanTable *huffRDYTable, JBIG2HuffmanTable *huffRSizeTable, Guint templ, int *atx, int *aty); void readPatternDictSeg(Guint segNum, Guint length); void readHalftoneRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs); void readGenericRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length); void mmrAddPixels(int a1, int blackPixels, int *codingLine, int *a0i, int w); void mmrAddPixelsNeg(int a1, int blackPixels, int *codingLine, int *a0i, int w); JBIG2Bitmap *readGenericBitmap(GBool mmr, int w, int h, int templ, GBool tpgdOn, GBool useSkip, JBIG2Bitmap *skip, int *atx, int *aty, int mmrDataLength); void readGenericRefinementRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs); JBIG2Bitmap *readGenericRefinementRegion(int w, int h, int templ, GBool tpgrOn, JBIG2Bitmap *refBitmap, int refDX, int refDY, int *atx, int *aty); void readPageInfoSeg(Guint length); void readEndOfStripeSeg(Guint length); void readProfilesSeg(Guint length); void readCodeTableSeg(Guint segNum, Guint length); void readExtensionSeg(Guint length); JBIG2Segment *findSegment(Guint segNum); void discardSegment(Guint segNum); void resetGenericStats(Guint templ, JArithmeticDecoderStats *prevStats); void resetRefinementStats(Guint templ, JArithmeticDecoderStats *prevStats); void resetIntStats(int symCodeLen); GBool readUByte(Guint *x); GBool readByte(int *x); GBool readUWord(Guint *x); GBool readULong(Guint *x); GBool readLong(int *x); Object globalsStream; Guint pageW, pageH, curPageH; Guint pageDefPixel; JBIG2Bitmap *pageBitmap; Guint defCombOp; GList *segments; // [JBIG2Segment] GList *globalSegments; // [JBIG2Segment] Stream *curStr; Guchar *dataPtr; Guchar *dataEnd; Guint byteCounter; JArithmeticDecoder *arithDecoder; JArithmeticDecoderStats *genericRegionStats; JArithmeticDecoderStats *refinementRegionStats; JArithmeticDecoderStats *iadhStats; JArithmeticDecoderStats *iadwStats; JArithmeticDecoderStats *iaexStats; JArithmeticDecoderStats *iaaiStats; JArithmeticDecoderStats *iadtStats; JArithmeticDecoderStats *iaitStats; JArithmeticDecoderStats *iafsStats; JArithmeticDecoderStats *iadsStats; JArithmeticDecoderStats *iardxStats; JArithmeticDecoderStats *iardyStats; JArithmeticDecoderStats *iardwStats; JArithmeticDecoderStats *iardhStats; JArithmeticDecoderStats *iariStats; JArithmeticDecoderStats *iaidStats; JBIG2HuffmanDecoder *huffDecoder; JBIG2MMRDecoder *mmrDecoder; }; #endif xpdf-3.03/xpdf/PSTokenizer.cc0000644000076400007640000000626311622305345015407 0ustar dereknderekn//======================================================================== // // PSTokenizer.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "PSTokenizer.h" //------------------------------------------------------------------------ // A '1' in this array means the character is white space. A '1' or // '2' means the character ends a name or command. static char specialChars[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx }; //------------------------------------------------------------------------ PSTokenizer::PSTokenizer(int (*getCharFuncA)(void *), void *dataA) { getCharFunc = getCharFuncA; data = dataA; charBuf = -1; } PSTokenizer::~PSTokenizer() { } GBool PSTokenizer::getToken(char *buf, int size, int *length) { GBool comment, backslash; int c; int i; // skip whitespace and comments comment = gFalse; while (1) { if ((c = getChar()) == EOF) { buf[0] = '\0'; *length = 0; return gFalse; } if (comment) { if (c == '\x0a' || c == '\x0d') { comment = gFalse; } } else if (c == '%') { comment = gTrue; } else if (specialChars[c] != 1) { break; } } // read a token i = 0; buf[i++] = c; if (c == '(') { backslash = gFalse; while ((c = lookChar()) != EOF) { if (i < size - 1) { buf[i++] = c; } getChar(); if (c == '\\') { backslash = gTrue; } else if (!backslash && c == ')') { break; } else { backslash = gFalse; } } } else if (c == '<') { while ((c = lookChar()) != EOF) { getChar(); if (i < size - 1 && specialChars[c] != 1) { buf[i++] = c; } if (c == '>') { break; } } } else if (c != '[' && c != ']') { while ((c = lookChar()) != EOF && !specialChars[c]) { getChar(); if (i < size - 1) { buf[i++] = c; } } } buf[i] = '\0'; *length = i; return gTrue; } int PSTokenizer::lookChar() { if (charBuf < 0) { charBuf = (*getCharFunc)(data); } return charBuf; } int PSTokenizer::getChar() { int c; if (charBuf < 0) { charBuf = (*getCharFunc)(data); } c = charBuf; charBuf = -1; return c; } xpdf-3.03/xpdf/Gfx.cc0000644000076400007640000036121511622305345013717 0ustar dereknderekn//======================================================================== // // Gfx.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "gmem.h" #include "GString.h" #include "GList.h" #include "GlobalParams.h" #include "CharTypes.h" #include "Object.h" #include "PDFDoc.h" #include "Array.h" #include "Dict.h" #include "Stream.h" #include "Lexer.h" #include "Parser.h" #include "GfxFont.h" #include "GfxState.h" #include "OutputDev.h" #include "Page.h" #include "Annot.h" #include "OptionalContent.h" #include "Error.h" #include "PDFDocEncoding.h" #include "Gfx.h" // the MSVC math.h doesn't define this #ifndef M_PI #define M_PI 3.14159265358979323846 #endif //------------------------------------------------------------------------ // constants //------------------------------------------------------------------------ // Max recursive depth for a function shading fill. #define functionMaxDepth 6 // Max delta allowed in any color component for a function shading fill. #define functionColorDelta (dblToCol(1 / 256.0)) // Max number of splits along the t axis for an axial shading fill. #define axialMaxSplits 256 // Max delta allowed in any color component for an axial shading fill. #define axialColorDelta (dblToCol(1 / 256.0)) // Max number of splits along the t axis for a radial shading fill. #define radialMaxSplits 256 // Max delta allowed in any color component for a radial shading fill. #define radialColorDelta (dblToCol(1 / 256.0)) // Max recursive depth for a Gouraud triangle shading fill. #define gouraudMaxDepth 6 // Max delta allowed in any color component for a Gouraud triangle // shading fill. #define gouraudColorDelta (dblToCol(1 / 256.0)) // Max recursive depth for a patch mesh shading fill. #define patchMaxDepth 6 // Max delta allowed in any color component for a patch mesh shading // fill. #define patchColorDelta (dblToCol(1 / 256.0)) //------------------------------------------------------------------------ // Operator table //------------------------------------------------------------------------ #ifdef WIN32 // this works around a bug in the VC7 compiler # pragma optimize("",off) #endif Operator Gfx::opTab[] = { {"\"", 3, {tchkNum, tchkNum, tchkString}, &Gfx::opMoveSetShowText}, {"'", 1, {tchkString}, &Gfx::opMoveShowText}, {"B", 0, {tchkNone}, &Gfx::opFillStroke}, {"B*", 0, {tchkNone}, &Gfx::opEOFillStroke}, {"BDC", 2, {tchkName, tchkProps}, &Gfx::opBeginMarkedContent}, {"BI", 0, {tchkNone}, &Gfx::opBeginImage}, {"BMC", 1, {tchkName}, &Gfx::opBeginMarkedContent}, {"BT", 0, {tchkNone}, &Gfx::opBeginText}, {"BX", 0, {tchkNone}, &Gfx::opBeginIgnoreUndef}, {"CS", 1, {tchkName}, &Gfx::opSetStrokeColorSpace}, {"DP", 2, {tchkName, tchkProps}, &Gfx::opMarkPoint}, {"Do", 1, {tchkName}, &Gfx::opXObject}, {"EI", 0, {tchkNone}, &Gfx::opEndImage}, {"EMC", 0, {tchkNone}, &Gfx::opEndMarkedContent}, {"ET", 0, {tchkNone}, &Gfx::opEndText}, {"EX", 0, {tchkNone}, &Gfx::opEndIgnoreUndef}, {"F", 0, {tchkNone}, &Gfx::opFill}, {"G", 1, {tchkNum}, &Gfx::opSetStrokeGray}, {"ID", 0, {tchkNone}, &Gfx::opImageData}, {"J", 1, {tchkInt}, &Gfx::opSetLineCap}, {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeCMYKColor}, {"M", 1, {tchkNum}, &Gfx::opSetMiterLimit}, {"MP", 1, {tchkName}, &Gfx::opMarkPoint}, {"Q", 0, {tchkNone}, &Gfx::opRestore}, {"RG", 3, {tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeRGBColor}, {"S", 0, {tchkNone}, &Gfx::opStroke}, {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetStrokeColor}, {"SCN", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN}, &Gfx::opSetStrokeColorN}, {"T*", 0, {tchkNone}, &Gfx::opTextNextLine}, {"TD", 2, {tchkNum, tchkNum}, &Gfx::opTextMoveSet}, {"TJ", 1, {tchkArray}, &Gfx::opShowSpaceText}, {"TL", 1, {tchkNum}, &Gfx::opSetTextLeading}, {"Tc", 1, {tchkNum}, &Gfx::opSetCharSpacing}, {"Td", 2, {tchkNum, tchkNum}, &Gfx::opTextMove}, {"Tf", 2, {tchkName, tchkNum}, &Gfx::opSetFont}, {"Tj", 1, {tchkString}, &Gfx::opShowText}, {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetTextMatrix}, {"Tr", 1, {tchkInt}, &Gfx::opSetTextRender}, {"Ts", 1, {tchkNum}, &Gfx::opSetTextRise}, {"Tw", 1, {tchkNum}, &Gfx::opSetWordSpacing}, {"Tz", 1, {tchkNum}, &Gfx::opSetHorizScaling}, {"W", 0, {tchkNone}, &Gfx::opClip}, {"W*", 0, {tchkNone}, &Gfx::opEOClip}, {"b", 0, {tchkNone}, &Gfx::opCloseFillStroke}, {"b*", 0, {tchkNone}, &Gfx::opCloseEOFillStroke}, {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opCurveTo}, {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opConcat}, {"cs", 1, {tchkName}, &Gfx::opSetFillColorSpace}, {"d", 2, {tchkArray, tchkNum}, &Gfx::opSetDash}, {"d0", 2, {tchkNum, tchkNum}, &Gfx::opSetCharWidth}, {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetCacheDevice}, {"f", 0, {tchkNone}, &Gfx::opFill}, {"f*", 0, {tchkNone}, &Gfx::opEOFill}, {"g", 1, {tchkNum}, &Gfx::opSetFillGray}, {"gs", 1, {tchkName}, &Gfx::opSetExtGState}, {"h", 0, {tchkNone}, &Gfx::opClosePath}, {"i", 1, {tchkNum}, &Gfx::opSetFlat}, {"j", 1, {tchkInt}, &Gfx::opSetLineJoin}, {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetFillCMYKColor}, {"l", 2, {tchkNum, tchkNum}, &Gfx::opLineTo}, {"m", 2, {tchkNum, tchkNum}, &Gfx::opMoveTo}, {"n", 0, {tchkNone}, &Gfx::opEndPath}, {"q", 0, {tchkNone}, &Gfx::opSave}, {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opRectangle}, {"rg", 3, {tchkNum, tchkNum, tchkNum}, &Gfx::opSetFillRGBColor}, {"ri", 1, {tchkName}, &Gfx::opSetRenderingIntent}, {"s", 0, {tchkNone}, &Gfx::opCloseStroke}, {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opSetFillColor}, {"scn", -33, {tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN, tchkSCN}, &Gfx::opSetFillColorN}, {"sh", 1, {tchkName}, &Gfx::opShFill}, {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opCurveTo1}, {"w", 1, {tchkNum}, &Gfx::opSetLineWidth}, {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum}, &Gfx::opCurveTo2}, }; #ifdef WIN32 // this works around a bug in the VC7 compiler # pragma optimize("",on) #endif #define numOps (sizeof(opTab) / sizeof(Operator)) //------------------------------------------------------------------------ // GfxResources //------------------------------------------------------------------------ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) { Object obj1, obj2; Ref r; if (resDict) { // build font dictionary fonts = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { obj1.fetch(xref, &obj2); if (obj2.isDict()) { r = obj1.getRef(); fonts = new GfxFontDict(xref, &r, obj2.getDict()); } obj2.free(); } else if (obj1.isDict()) { fonts = new GfxFontDict(xref, NULL, obj1.getDict()); } obj1.free(); // get XObject dictionary resDict->lookup("XObject", &xObjDict); // get color space dictionary resDict->lookup("ColorSpace", &colorSpaceDict); // get pattern dictionary resDict->lookup("Pattern", &patternDict); // get shading dictionary resDict->lookup("Shading", &shadingDict); // get graphics state parameter dictionary resDict->lookup("ExtGState", &gStateDict); // get properties dictionary resDict->lookup("Properties", &propsDict); } else { fonts = NULL; xObjDict.initNull(); colorSpaceDict.initNull(); patternDict.initNull(); shadingDict.initNull(); gStateDict.initNull(); propsDict.initNull(); } next = nextA; } GfxResources::~GfxResources() { if (fonts) { delete fonts; } xObjDict.free(); colorSpaceDict.free(); patternDict.free(); shadingDict.free(); gStateDict.free(); propsDict.free(); } GfxFont *GfxResources::lookupFont(char *name) { GfxFont *font; GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->fonts) { if ((font = resPtr->fonts->lookup(name))) return font; } } error(errSyntaxError, -1, "Unknown font tag '{0:s}'", name); return NULL; } GBool GfxResources::lookupXObject(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->xObjDict.isDict()) { if (!resPtr->xObjDict.dictLookup(name, obj)->isNull()) return gTrue; obj->free(); } } error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name); return gFalse; } GBool GfxResources::lookupXObjectNF(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->xObjDict.isDict()) { if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull()) return gTrue; obj->free(); } } error(errSyntaxError, -1, "XObject '{0:s}' is unknown", name); return gFalse; } void GfxResources::lookupColorSpace(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->colorSpaceDict.isDict()) { if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) { return; } obj->free(); } } obj->initNull(); } GfxPattern *GfxResources::lookupPattern(char *name) { GfxResources *resPtr; GfxPattern *pattern; Object obj; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->patternDict.isDict()) { if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) { pattern = GfxPattern::parse(&obj); obj.free(); return pattern; } obj.free(); } } error(errSyntaxError, -1, "Unknown pattern '{0:s}'", name); return NULL; } GfxShading *GfxResources::lookupShading(char *name) { GfxResources *resPtr; GfxShading *shading; Object obj; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->shadingDict.isDict()) { if (!resPtr->shadingDict.dictLookup(name, &obj)->isNull()) { shading = GfxShading::parse(&obj); obj.free(); return shading; } obj.free(); } } error(errSyntaxError, -1, "Unknown shading '{0:s}'", name); return NULL; } GBool GfxResources::lookupGState(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->gStateDict.isDict()) { if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) { return gTrue; } obj->free(); } } error(errSyntaxError, -1, "ExtGState '{0:s}' is unknown", name); return gFalse; } GBool GfxResources::lookupPropertiesNF(char *name, Object *obj) { GfxResources *resPtr; for (resPtr = this; resPtr; resPtr = resPtr->next) { if (resPtr->propsDict.isDict()) { if (!resPtr->propsDict.dictLookupNF(name, obj)->isNull()) { return gTrue; } obj->free(); } } error(errSyntaxError, -1, "Properties '{0:s}' is unknown", name); return gFalse; } //------------------------------------------------------------------------ // Gfx //------------------------------------------------------------------------ Gfx::Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { int i; doc = docA; xref = doc->getXRef(); subPage = gFalse; printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize out = outA; state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown()); fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; out->startPage(pageNum, state); out->setDefaultCTM(state->getCTM()); out->updateAll(state); for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } formDepth = 0; textClipBBoxEmpty = gTrue; markedContentStack = new GList(); ocState = gTrue; parser = NULL; abortCheckCbk = abortCheckCbkA; abortCheckCbkData = abortCheckCbkDataA; // set crop box if (cropBox) { state->moveTo(cropBox->x1, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y2); state->lineTo(cropBox->x1, cropBox->y2); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } } Gfx::Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data), void *abortCheckCbkDataA) { int i; doc = docA; xref = doc->getXRef(); subPage = gTrue; printCommands = globalParams->getPrintCommands(); // start the resource stack res = new GfxResources(xref, resDict, NULL); // initialize out = outA; state = new GfxState(72, 72, box, 0, gFalse); fontChanged = gFalse; clip = clipNone; ignoreUndef = 0; for (i = 0; i < 6; ++i) { baseMatrix[i] = state->getCTM()[i]; } formDepth = 0; textClipBBoxEmpty = gTrue; markedContentStack = new GList(); ocState = gTrue; parser = NULL; abortCheckCbk = abortCheckCbkA; abortCheckCbkData = abortCheckCbkDataA; // set crop box if (cropBox) { state->moveTo(cropBox->x1, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y1); state->lineTo(cropBox->x2, cropBox->y2); state->lineTo(cropBox->x1, cropBox->y2); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } } Gfx::~Gfx() { if (!subPage) { out->endPage(); } while (state->hasSaves()) { restoreState(); } delete state; while (res) { popResources(); } deleteGList(markedContentStack, GfxMarkedContent); } void Gfx::display(Object *obj, GBool topLevel) { Object obj2; int i; if (obj->isArray()) { for (i = 0; i < obj->arrayGetLength(); ++i) { obj->arrayGet(i, &obj2); if (!obj2.isStream()) { error(errSyntaxError, -1, "Weird page contents"); obj2.free(); return; } obj2.free(); } } else if (!obj->isStream()) { error(errSyntaxError, -1, "Weird page contents"); return; } parser = new Parser(xref, new Lexer(xref, obj), gFalse); go(topLevel); delete parser; parser = NULL; } void Gfx::go(GBool topLevel) { Object obj; Object args[maxArgs]; int numArgs, i; int lastAbortCheck; // scan a sequence of objects updateLevel = 1; // make sure even empty pages trigger a call to dump() lastAbortCheck = 0; numArgs = 0; parser->getObj(&obj); while (!obj.isEOF()) { // got a command - execute it if (obj.isCmd()) { if (printCommands) { obj.print(stdout); for (i = 0; i < numArgs; ++i) { printf(" "); args[i].print(stdout); } printf("\n"); fflush(stdout); } execOp(&obj, args, numArgs); obj.free(); for (i = 0; i < numArgs; ++i) args[i].free(); numArgs = 0; // periodically update display if (++updateLevel >= 20000) { out->dump(); updateLevel = 0; } // check for an abort if (abortCheckCbk) { if (updateLevel - lastAbortCheck > 10) { if ((*abortCheckCbk)(abortCheckCbkData)) { break; } lastAbortCheck = updateLevel; } } // got an argument - save it } else if (numArgs < maxArgs) { args[numArgs++] = obj; // too many arguments - something is wrong } else { error(errSyntaxError, getPos(), "Too many args in content stream"); if (printCommands) { printf("throwing away arg: "); obj.print(stdout); printf("\n"); fflush(stdout); } obj.free(); } // grab the next object parser->getObj(&obj); } obj.free(); // args at end with no command if (numArgs > 0) { error(errSyntaxError, getPos(), "Leftover args in content stream"); if (printCommands) { printf("%d leftovers:", numArgs); for (i = 0; i < numArgs; ++i) { printf(" "); args[i].print(stdout); } printf("\n"); fflush(stdout); } for (i = 0; i < numArgs; ++i) args[i].free(); } // update display if (topLevel && updateLevel > 0) { out->dump(); } } void Gfx::execOp(Object *cmd, Object args[], int numArgs) { Operator *op; char *name; Object *argPtr; int i; // find operator name = cmd->getCmd(); if (!(op = findOp(name))) { if (ignoreUndef == 0) error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name); return; } // type check args argPtr = args; if (op->numArgs >= 0) { if (numArgs < op->numArgs) { error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:s}' operator", numArgs, name); return; } if (numArgs > op->numArgs) { #if 0 error(errSyntaxWarning, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name); #endif argPtr += numArgs - op->numArgs; numArgs = op->numArgs; } } else { if (numArgs > -op->numArgs) { error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name); return; } } for (i = 0; i < numArgs; ++i) { if (!checkArg(&argPtr[i], op->tchk[i])) { error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})", i, name, argPtr[i].getTypeName()); return; } } // do it (this->*op->func)(argPtr, numArgs); } Operator *Gfx::findOp(char *name) { int a, b, m, cmp; a = -1; b = numOps; cmp = 0; // make gcc happy // invariant: opTab[a] < name < opTab[b] while (b - a > 1) { m = (a + b) / 2; cmp = strcmp(opTab[m].name, name); if (cmp < 0) a = m; else if (cmp > 0) b = m; else a = b = m; } if (cmp != 0) return NULL; return &opTab[a]; } GBool Gfx::checkArg(Object *arg, TchkType type) { switch (type) { case tchkBool: return arg->isBool(); case tchkInt: return arg->isInt(); case tchkNum: return arg->isNum(); case tchkString: return arg->isString(); case tchkName: return arg->isName(); case tchkArray: return arg->isArray(); case tchkProps: return arg->isDict() || arg->isName(); case tchkSCN: return arg->isNum() || arg->isName(); case tchkNone: return gFalse; } return gFalse; } int Gfx::getPos() { return parser ? parser->getPos() : -1; } //------------------------------------------------------------------------ // graphics state operators //------------------------------------------------------------------------ void Gfx::opSave(Object args[], int numArgs) { saveState(); } void Gfx::opRestore(Object args[], int numArgs) { restoreState(); } void Gfx::opConcat(Object args[], int numArgs) { state->concatCTM(args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); out->updateCTM(state, args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); fontChanged = gTrue; } void Gfx::opSetDash(Object args[], int numArgs) { Array *a; int length; Object obj; double *dash; int i; a = args[0].getArray(); length = a->getLength(); if (length == 0) { dash = NULL; } else { dash = (double *)gmallocn(length, sizeof(double)); for (i = 0; i < length; ++i) { dash[i] = a->get(i, &obj)->getNum(); obj.free(); } } state->setLineDash(dash, length, args[1].getNum()); out->updateLineDash(state); } void Gfx::opSetFlat(Object args[], int numArgs) { state->setFlatness((int)args[0].getNum()); out->updateFlatness(state); } void Gfx::opSetLineJoin(Object args[], int numArgs) { state->setLineJoin(args[0].getInt()); out->updateLineJoin(state); } void Gfx::opSetLineCap(Object args[], int numArgs) { state->setLineCap(args[0].getInt()); out->updateLineCap(state); } void Gfx::opSetMiterLimit(Object args[], int numArgs) { state->setMiterLimit(args[0].getNum()); out->updateMiterLimit(state); } void Gfx::opSetLineWidth(Object args[], int numArgs) { state->setLineWidth(args[0].getNum()); out->updateLineWidth(state); } void Gfx::opSetExtGState(Object args[], int numArgs) { Object obj1, obj2, obj3, obj4, obj5; Object args2[2]; GfxBlendMode mode; GBool haveFillOP; Function *funcs[4]; GfxColor backdropColor; GBool haveBackdropColor; GfxColorSpace *blendingColorSpace; GBool alpha, isolated, knockout; double opac; int i; if (!res->lookupGState(args[0].getName(), &obj1)) { return; } if (!obj1.isDict()) { error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type", args[0].getName()); obj1.free(); return; } if (printCommands) { printf(" gfx state dict: "); obj1.print(); printf("\n"); } // parameters that are also set by individual PDF operators if (obj1.dictLookup("LW", &obj2)->isNum()) { opSetLineWidth(&obj2, 1); } obj2.free(); if (obj1.dictLookup("LC", &obj2)->isInt()) { opSetLineCap(&obj2, 1); } obj2.free(); if (obj1.dictLookup("LJ", &obj2)->isInt()) { opSetLineJoin(&obj2, 1); } obj2.free(); if (obj1.dictLookup("ML", &obj2)->isNum()) { opSetMiterLimit(&obj2, 1); } obj2.free(); if (obj1.dictLookup("D", &obj2)->isArray() && obj2.arrayGetLength() == 2) { obj2.arrayGet(0, &args2[0]); obj2.arrayGet(1, &args2[1]); if (args2[0].isArray() && args2[1].isNum()) { opSetDash(args2, 2); } args2[0].free(); args2[1].free(); } obj2.free(); #if 0 //~ need to add a new version of GfxResources::lookupFont() that //~ takes an indirect ref instead of a name if (obj1.dictLookup("Font", &obj2)->isArray() && obj2.arrayGetLength() == 2) { obj2.arrayGet(0, &args2[0]); obj2.arrayGet(1, &args2[1]); if (args2[0].isDict() && args2[1].isNum()) { opSetFont(args2, 2); } args2[0].free(); args2[1].free(); } obj2.free(); #endif if (obj1.dictLookup("FL", &obj2)->isNum()) { opSetFlat(&obj2, 1); } obj2.free(); // transparency support: blend mode, fill/stroke opacity if (!obj1.dictLookup("BM", &obj2)->isNull()) { if (state->parseBlendMode(&obj2, &mode)) { state->setBlendMode(mode); out->updateBlendMode(state); } else { error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState"); } } obj2.free(); if (obj1.dictLookup("ca", &obj2)->isNum()) { opac = obj2.getNum(); state->setFillOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac); out->updateFillOpacity(state); } obj2.free(); if (obj1.dictLookup("CA", &obj2)->isNum()) { opac = obj2.getNum(); state->setStrokeOpacity(opac < 0 ? 0 : opac > 1 ? 1 : opac); out->updateStrokeOpacity(state); } obj2.free(); // fill/stroke overprint, overprint mode if ((haveFillOP = (obj1.dictLookup("op", &obj2)->isBool()))) { state->setFillOverprint(obj2.getBool()); out->updateFillOverprint(state); } obj2.free(); if (obj1.dictLookup("OP", &obj2)->isBool()) { state->setStrokeOverprint(obj2.getBool()); out->updateStrokeOverprint(state); if (!haveFillOP) { state->setFillOverprint(obj2.getBool()); out->updateFillOverprint(state); } } obj2.free(); if (obj1.dictLookup("OPM", &obj2)->isInt()) { state->setOverprintMode(obj2.getInt()); out->updateOverprintMode(state); } obj2.free(); // stroke adjust if (obj1.dictLookup("SA", &obj2)->isBool()) { state->setStrokeAdjust(obj2.getBool()); out->updateStrokeAdjust(state); } obj2.free(); // transfer function if (obj1.dictLookup("TR2", &obj2)->isNull()) { obj2.free(); obj1.dictLookup("TR", &obj2); } if (obj2.isName("Default") || obj2.isName("Identity")) { funcs[0] = funcs[1] = funcs[2] = funcs[3] = NULL; state->setTransfer(funcs); out->updateTransfer(state); } else if (obj2.isArray() && obj2.arrayGetLength() == 4) { for (i = 0; i < 4; ++i) { obj2.arrayGet(i, &obj3); funcs[i] = Function::parse(&obj3); obj3.free(); if (!funcs[i]) { break; } } if (i == 4) { state->setTransfer(funcs); out->updateTransfer(state); } } else if (obj2.isName() || obj2.isDict() || obj2.isStream()) { if ((funcs[0] = Function::parse(&obj2))) { funcs[1] = funcs[2] = funcs[3] = NULL; state->setTransfer(funcs); out->updateTransfer(state); } } else if (!obj2.isNull()) { error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState"); } obj2.free(); // soft mask if (!obj1.dictLookup("SMask", &obj2)->isNull()) { if (obj2.isName("None")) { out->clearSoftMask(state); } else if (obj2.isDict()) { if (obj2.dictLookup("S", &obj3)->isName("Alpha")) { alpha = gTrue; } else { // "Luminosity" alpha = gFalse; } obj3.free(); funcs[0] = NULL; if (!obj2.dictLookup("TR", &obj3)->isNull()) { if (obj3.isName("Default") || obj3.isName("Identity")) { funcs[0] = NULL; } else { funcs[0] = Function::parse(&obj3); if (funcs[0]->getInputSize() != 1 || funcs[0]->getOutputSize() != 1) { error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState"); delete funcs[0]; funcs[0] = NULL; } } } obj3.free(); if ((haveBackdropColor = obj2.dictLookup("BC", &obj3)->isArray())) { for (i = 0; i < gfxColorMaxComps; ++i) { backdropColor.c[i] = 0; } for (i = 0; i < obj3.arrayGetLength() && i < gfxColorMaxComps; ++i) { obj3.arrayGet(i, &obj4); if (obj4.isNum()) { backdropColor.c[i] = dblToCol(obj4.getNum()); } obj4.free(); } } obj3.free(); if (obj2.dictLookup("G", &obj3)->isStream()) { if (obj3.streamGetDict()->lookup("Group", &obj4)->isDict()) { blendingColorSpace = NULL; isolated = knockout = gFalse; if (!obj4.dictLookup("CS", &obj5)->isNull()) { blendingColorSpace = GfxColorSpace::parse(&obj5); } obj5.free(); if (obj4.dictLookup("I", &obj5)->isBool()) { isolated = obj5.getBool(); } obj5.free(); if (obj4.dictLookup("K", &obj5)->isBool()) { knockout = obj5.getBool(); } obj5.free(); if (!haveBackdropColor) { if (blendingColorSpace) { blendingColorSpace->getDefaultColor(&backdropColor); } else { //~ need to get the parent or default color space (?) for (i = 0; i < gfxColorMaxComps; ++i) { backdropColor.c[i] = 0; } } } doSoftMask(&obj3, alpha, blendingColorSpace, isolated, knockout, funcs[0], &backdropColor); if (funcs[0]) { delete funcs[0]; } } else { error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group"); } obj4.free(); } else { error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group"); } obj3.free(); } else if (!obj2.isNull()) { error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState"); } } obj2.free(); obj1.free(); } void Gfx::doSoftMask(Object *str, GBool alpha, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, Function *transferFunc, GfxColor *backdropColor) { Dict *dict, *resDict; double m[6], bbox[4]; Object obj1, obj2; int i; // check for excessive recursion if (formDepth > 20) { return; } // get stream dict dict = str->streamGetDict(); // check form type dict->lookup("FormType", &obj1); if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { error(errSyntaxError, getPos(), "Unknown form type"); } obj1.free(); // get bounding box dict->lookup("BBox", &obj1); if (!obj1.isArray()) { obj1.free(); error(errSyntaxError, getPos(), "Bad form bounding box"); return; } for (i = 0; i < 4; ++i) { obj1.arrayGet(i, &obj2); bbox[i] = obj2.getNum(); obj2.free(); } obj1.free(); // get matrix dict->lookup("Matrix", &obj1); if (obj1.isArray()) { for (i = 0; i < 6; ++i) { obj1.arrayGet(i, &obj2); m[i] = obj2.getNum(); obj2.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0; } obj1.free(); // get resources dict->lookup("Resources", &obj1); resDict = obj1.isDict() ? obj1.getDict() : (Dict *)NULL; // draw it ++formDepth; drawForm(str, resDict, m, bbox, gTrue, gTrue, blendingColorSpace, isolated, knockout, alpha, transferFunc, backdropColor); --formDepth; if (blendingColorSpace) { delete blendingColorSpace; } obj1.free(); } void Gfx::opSetRenderingIntent(Object args[], int numArgs) { } //------------------------------------------------------------------------ // color operators //------------------------------------------------------------------------ void Gfx::opSetFillGray(Object args[], int numArgs) { GfxColor color; state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceGrayColorSpace()); out->updateFillColorSpace(state); color.c[0] = dblToCol(args[0].getNum()); state->setFillColor(&color); out->updateFillColor(state); } void Gfx::opSetStrokeGray(Object args[], int numArgs) { GfxColor color; state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); out->updateStrokeColorSpace(state); color.c[0] = dblToCol(args[0].getNum()); state->setStrokeColor(&color); out->updateStrokeColor(state); } void Gfx::opSetFillCMYKColor(Object args[], int numArgs) { GfxColor color; int i; state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceCMYKColorSpace()); out->updateFillColorSpace(state); for (i = 0; i < 4; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); } void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) { GfxColor color; int i; state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace()); out->updateStrokeColorSpace(state); for (i = 0; i < 4; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); } void Gfx::opSetFillRGBColor(Object args[], int numArgs) { GfxColor color; int i; state->setFillPattern(NULL); state->setFillColorSpace(new GfxDeviceRGBColorSpace()); out->updateFillColorSpace(state); for (i = 0; i < 3; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); } void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) { GfxColor color; int i; state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); out->updateStrokeColorSpace(state); for (i = 0; i < 3; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); } void Gfx::opSetFillColorSpace(Object args[], int numArgs) { Object obj; GfxColorSpace *colorSpace; GfxColor color; state->setFillPattern(NULL); res->lookupColorSpace(args[0].getName(), &obj); if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0]); } else { colorSpace = GfxColorSpace::parse(&obj); } obj.free(); if (colorSpace) { state->setFillColorSpace(colorSpace); out->updateFillColorSpace(state); colorSpace->getDefaultColor(&color); state->setFillColor(&color); out->updateFillColor(state); } else { error(errSyntaxError, getPos(), "Bad color space (fill)"); } } void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) { Object obj; GfxColorSpace *colorSpace; GfxColor color; state->setStrokePattern(NULL); res->lookupColorSpace(args[0].getName(), &obj); if (obj.isNull()) { colorSpace = GfxColorSpace::parse(&args[0]); } else { colorSpace = GfxColorSpace::parse(&obj); } obj.free(); if (colorSpace) { state->setStrokeColorSpace(colorSpace); out->updateStrokeColorSpace(state); colorSpace->getDefaultColor(&color); state->setStrokeColor(&color); out->updateStrokeColor(state); } else { error(errSyntaxError, getPos(), "Bad color space (stroke)"); } } void Gfx::opSetFillColor(Object args[], int numArgs) { GfxColor color; int i; if (numArgs != state->getFillColorSpace()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command"); return; } state->setFillPattern(NULL); for (i = 0; i < numArgs; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setFillColor(&color); out->updateFillColor(state); } void Gfx::opSetStrokeColor(Object args[], int numArgs) { GfxColor color; int i; if (numArgs != state->getStrokeColorSpace()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command"); return; } state->setStrokePattern(NULL); for (i = 0; i < numArgs; ++i) { color.c[i] = dblToCol(args[i].getNum()); } state->setStrokeColor(&color); out->updateStrokeColor(state); } void Gfx::opSetFillColorN(Object args[], int numArgs) { GfxColor color; GfxPattern *pattern; int i; if (state->getFillColorSpace()->getMode() == csPattern) { if (numArgs > 1) { if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() || numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace()) ->getUnder()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command"); return; } for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) { if (args[i].isNum()) { color.c[i] = dblToCol(args[i].getNum()); } } state->setFillColor(&color); out->updateFillColor(state); } if (args[numArgs-1].isName() && (pattern = res->lookupPattern(args[numArgs-1].getName()))) { state->setFillPattern(pattern); } } else { if (numArgs != state->getFillColorSpace()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command"); return; } state->setFillPattern(NULL); for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) { if (args[i].isNum()) { color.c[i] = dblToCol(args[i].getNum()); } } state->setFillColor(&color); out->updateFillColor(state); } } void Gfx::opSetStrokeColorN(Object args[], int numArgs) { GfxColor color; GfxPattern *pattern; int i; if (state->getStrokeColorSpace()->getMode() == csPattern) { if (numArgs > 1) { if (!((GfxPatternColorSpace *)state->getStrokeColorSpace()) ->getUnder() || numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace()) ->getUnder()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command"); return; } for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) { if (args[i].isNum()) { color.c[i] = dblToCol(args[i].getNum()); } } state->setStrokeColor(&color); out->updateStrokeColor(state); } if (args[numArgs-1].isName() && (pattern = res->lookupPattern(args[numArgs-1].getName()))) { state->setStrokePattern(pattern); } } else { if (numArgs != state->getStrokeColorSpace()->getNComps()) { error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command"); return; } state->setStrokePattern(NULL); for (i = 0; i < numArgs && i < gfxColorMaxComps; ++i) { if (args[i].isNum()) { color.c[i] = dblToCol(args[i].getNum()); } } state->setStrokeColor(&color); out->updateStrokeColor(state); } } //------------------------------------------------------------------------ // path segment operators //------------------------------------------------------------------------ void Gfx::opMoveTo(Object args[], int numArgs) { state->moveTo(args[0].getNum(), args[1].getNum()); } void Gfx::opLineTo(Object args[], int numArgs) { if (!state->isCurPt()) { error(errSyntaxError, getPos(), "No current point in lineto"); return; } state->lineTo(args[0].getNum(), args[1].getNum()); } void Gfx::opCurveTo(Object args[], int numArgs) { double x1, y1, x2, y2, x3, y3; if (!state->isCurPt()) { error(errSyntaxError, getPos(), "No current point in curveto"); return; } x1 = args[0].getNum(); y1 = args[1].getNum(); x2 = args[2].getNum(); y2 = args[3].getNum(); x3 = args[4].getNum(); y3 = args[5].getNum(); state->curveTo(x1, y1, x2, y2, x3, y3); } void Gfx::opCurveTo1(Object args[], int numArgs) { double x1, y1, x2, y2, x3, y3; if (!state->isCurPt()) { error(errSyntaxError, getPos(), "No current point in curveto1"); return; } x1 = state->getCurX(); y1 = state->getCurY(); x2 = args[0].getNum(); y2 = args[1].getNum(); x3 = args[2].getNum(); y3 = args[3].getNum(); state->curveTo(x1, y1, x2, y2, x3, y3); } void Gfx::opCurveTo2(Object args[], int numArgs) { double x1, y1, x2, y2, x3, y3; if (!state->isCurPt()) { error(errSyntaxError, getPos(), "No current point in curveto2"); return; } x1 = args[0].getNum(); y1 = args[1].getNum(); x2 = args[2].getNum(); y2 = args[3].getNum(); x3 = x2; y3 = y2; state->curveTo(x1, y1, x2, y2, x3, y3); } void Gfx::opRectangle(Object args[], int numArgs) { double x, y, w, h; x = args[0].getNum(); y = args[1].getNum(); w = args[2].getNum(); h = args[3].getNum(); state->moveTo(x, y); state->lineTo(x + w, y); state->lineTo(x + w, y + h); state->lineTo(x, y + h); state->closePath(); } void Gfx::opClosePath(Object args[], int numArgs) { if (!state->isCurPt()) { error(errSyntaxError, getPos(), "No current point in closepath"); return; } state->closePath(); } //------------------------------------------------------------------------ // path painting operators //------------------------------------------------------------------------ void Gfx::opEndPath(Object args[], int numArgs) { doEndPath(); } void Gfx::opStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in stroke"); return; } if (state->isPath()) { if (ocState) { if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::opCloseStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in closepath/stroke"); return; } if (state->isPath()) { state->closePath(); if (ocState) { if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::opFill(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in fill"); return; } if (state->isPath()) { if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gFalse); } else { out->fill(state); } } } doEndPath(); } void Gfx::opEOFill(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in eofill"); return; } if (state->isPath()) { if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } } } doEndPath(); } void Gfx::opFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in fill/stroke"); return; } if (state->isPath()) { if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gFalse); } else { out->fill(state); } if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::opCloseFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in closepath/fill/stroke"); return; } if (state->isPath()) { state->closePath(); if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gFalse); } else { out->fill(state); } if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::opEOFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in eofill/stroke"); return; } if (state->isPath()) { if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::opCloseEOFillStroke(Object args[], int numArgs) { if (!state->isCurPt()) { //error(errSyntaxError, getPos(), "No path in closepath/eofill/stroke"); return; } if (state->isPath()) { state->closePath(); if (ocState) { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternFill(gTrue); } else { out->eoFill(state); } if (state->getStrokeColorSpace()->getMode() == csPattern) { doPatternStroke(); } else { out->stroke(state); } } } doEndPath(); } void Gfx::doPatternFill(GBool eoFill) { GfxPattern *pattern; // this is a bit of a kludge -- patterns can be really slow, so we // skip them if we're only doing text extraction, since they almost // certainly don't contain any text if (!out->needNonText()) { return; } if (!(pattern = state->getFillPattern())) { return; } switch (pattern->getType()) { case 1: doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, eoFill, gFalse); break; case 2: doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, eoFill, gFalse); break; default: error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill", pattern->getType()); break; } } void Gfx::doPatternStroke() { GfxPattern *pattern; // this is a bit of a kludge -- patterns can be really slow, so we // skip them if we're only doing text extraction, since they almost // certainly don't contain any text if (!out->needNonText()) { return; } if (!(pattern = state->getStrokePattern())) { return; } switch (pattern->getType()) { case 1: doTilingPatternFill((GfxTilingPattern *)pattern, gTrue, gFalse, gFalse); break; case 2: doShadingPatternFill((GfxShadingPattern *)pattern, gTrue, gFalse, gFalse); break; default: error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in stroke", pattern->getType()); break; } } void Gfx::doPatternText() { GfxPattern *pattern; // this is a bit of a kludge -- patterns can be really slow, so we // skip them if we're only doing text extraction, since they almost // certainly don't contain any text if (!out->needNonText()) { return; } if (!(pattern = state->getFillPattern())) { return; } switch (pattern->getType()) { case 1: doTilingPatternFill((GfxTilingPattern *)pattern, gFalse, gFalse, gTrue); break; case 2: doShadingPatternFill((GfxShadingPattern *)pattern, gFalse, gFalse, gTrue); break; default: error(errSyntaxError, getPos(), "Unknown pattern type ({0:d}) in fill", pattern->getType()); break; } } void Gfx::doPatternImageMask(Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { saveState(); out->setSoftMaskFromImageMask(state, ref, str, width, height, invert, inlineImg); state->clearPath(); state->moveTo(0, 0); state->lineTo(1, 0); state->lineTo(1, 1); state->lineTo(0, 1); state->closePath(); doPatternFill(gTrue); restoreState(); } void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool stroke, GBool eoFill, GBool text) { GfxPatternColorSpace *patCS; GfxColorSpace *cs; GfxState *savedState; double xMin, yMin, xMax, yMax, x, y, x1, y1; double cxMin, cyMin, cxMax, cyMax; int xi0, yi0, xi1, yi1, xi, yi; double *ctm, *btm, *ptm; double m[6], ictm[6], m1[6], imb[6]; double det; double xstep, ystep; int i; // get color space patCS = (GfxPatternColorSpace *)(stroke ? state->getStrokeColorSpace() : state->getFillColorSpace()); // construct a (pattern space) -> (current space) transform matrix ctm = state->getCTM(); btm = baseMatrix; ptm = tPat->getMatrix(); // iCTM = invert CTM det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); ictm[0] = ctm[3] * det; ictm[1] = -ctm[1] * det; ictm[2] = -ctm[2] * det; ictm[3] = ctm[0] * det; ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; // m1 = PTM * BTM = PTM * base transform matrix m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; // m = m1 * iCTM = (PTM * BTM) * (iCTM) m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; // construct a (device space) -> (pattern space) transform matrix det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); imb[0] = m1[3] * det; imb[1] = -m1[1] * det; imb[2] = -m1[2] * det; imb[3] = m1[0] * det; imb[4] = (m1[2] * m1[5] - m1[3] * m1[4]) * det; imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; // save current graphics state savedState = saveStateStack(); // set underlying color space (for uncolored tiling patterns); set // various other parameters (stroke color, line width) to match // Adobe's behavior state->setFillPattern(NULL); state->setStrokePattern(NULL); if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) { state->setFillColorSpace(cs->copy()); out->updateFillColorSpace(state); state->setStrokeColorSpace(cs->copy()); out->updateStrokeColorSpace(state); state->setStrokeColor(state->getFillColor()); out->updateFillColor(state); out->updateStrokeColor(state); } else { state->setFillColorSpace(new GfxDeviceGrayColorSpace()); out->updateFillColorSpace(state); state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); out->updateStrokeColorSpace(state); } if (!stroke) { state->setLineWidth(0); out->updateLineWidth(state); } // clip to current path if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); } else if (!text) { state->clip(); if (eoFill) { out->eoClip(state); } else { out->clip(state); } } state->clearPath(); // get the clip region, check for empty state->getClipBBox(&cxMin, &cyMin, &cxMax, &cyMax); if (cxMin > cxMax || cyMin > cyMax) { goto err; } // transform clip region bbox to pattern space xMin = xMax = cxMin * imb[0] + cyMin * imb[2] + imb[4]; yMin = yMax = cxMin * imb[1] + cyMin * imb[3] + imb[5]; x1 = cxMin * imb[0] + cyMax * imb[2] + imb[4]; y1 = cxMin * imb[1] + cyMax * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } x1 = cxMax * imb[0] + cyMin * imb[2] + imb[4]; y1 = cxMax * imb[1] + cyMin * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } x1 = cxMax * imb[0] + cyMax * imb[2] + imb[4]; y1 = cxMax * imb[1] + cyMax * imb[3] + imb[5]; if (x1 < xMin) { xMin = x1; } else if (x1 > xMax) { xMax = x1; } if (y1 < yMin) { yMin = y1; } else if (y1 > yMax) { yMax = y1; } // draw the pattern //~ this should treat negative steps differently -- start at right/top //~ edge instead of left/bottom (?) xstep = fabs(tPat->getXStep()); ystep = fabs(tPat->getYStep()); xi0 = (int)ceil((xMin - tPat->getBBox()[2]) / xstep); xi1 = (int)floor((xMax - tPat->getBBox()[0]) / xstep) + 1; yi0 = (int)ceil((yMin - tPat->getBBox()[3]) / ystep); yi1 = (int)floor((yMax - tPat->getBBox()[1]) / ystep) + 1; for (i = 0; i < 4; ++i) { m1[i] = m[i]; } if (out->useTilingPatternFill()) { m1[4] = m[4]; m1[5] = m[5]; out->tilingPatternFill(state, this, tPat->getContentStream(), tPat->getPaintType(), tPat->getResDict(), m1, tPat->getBBox(), xi0, yi0, xi1, yi1, xstep, ystep); } else { for (yi = yi0; yi < yi1; ++yi) { for (xi = xi0; xi < xi1; ++xi) { x = xi * xstep; y = yi * ystep; m1[4] = x * m[0] + y * m[2] + m[4]; m1[5] = x * m[1] + y * m[3] + m[5]; drawForm(tPat->getContentStream(), tPat->getResDict(), m1, tPat->getBBox()); } } } // restore graphics state err: restoreStateStack(savedState); } void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool stroke, GBool eoFill, GBool text) { GfxShading *shading; GfxState *savedState; double *ctm, *btm, *ptm; double m[6], ictm[6], m1[6]; double xMin, yMin, xMax, yMax; double det; shading = sPat->getShading(); // save current graphics state savedState = saveStateStack(); // clip to current path if (stroke) { state->clipToStrokePath(); out->clipToStrokePath(state); } else if (!text) { state->clip(); if (eoFill) { out->eoClip(state); } else { out->clip(state); } } state->clearPath(); // construct a (pattern space) -> (current space) transform matrix ctm = state->getCTM(); btm = baseMatrix; ptm = sPat->getMatrix(); // iCTM = invert CTM det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]); ictm[0] = ctm[3] * det; ictm[1] = -ctm[1] * det; ictm[2] = -ctm[2] * det; ictm[3] = ctm[0] * det; ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det; ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det; // m1 = PTM * BTM = PTM * base transform matrix m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2]; m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3]; m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2]; m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3]; m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4]; m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5]; // m = m1 * iCTM = (PTM * BTM) * (iCTM) m[0] = m1[0] * ictm[0] + m1[1] * ictm[2]; m[1] = m1[0] * ictm[1] + m1[1] * ictm[3]; m[2] = m1[2] * ictm[0] + m1[3] * ictm[2]; m[3] = m1[2] * ictm[1] + m1[3] * ictm[3]; m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; // set the new matrix state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]); out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]); // clip to bbox if (shading->getHasBBox()) { shading->getBBox(&xMin, &yMin, &xMax, &yMax); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } // set the color space state->setFillColorSpace(shading->getColorSpace()->copy()); out->updateFillColorSpace(state); // background color fill if (shading->getHasBackground()) { state->setFillColor(shading->getBackground()); out->updateFillColor(state); state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); out->fill(state); state->clearPath(); } #if 1 //~tmp: turn off anti-aliasing temporarily out->setInShading(gTrue); #endif // do shading type-specific operations switch (shading->getType()) { case 1: doFunctionShFill((GfxFunctionShading *)shading); break; case 2: doAxialShFill((GfxAxialShading *)shading); break; case 3: doRadialShFill((GfxRadialShading *)shading); break; case 4: case 5: doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); break; case 6: case 7: doPatchMeshShFill((GfxPatchMeshShading *)shading); break; } #if 1 //~tmp: turn off anti-aliasing temporarily out->setInShading(gFalse); #endif // restore graphics state restoreStateStack(savedState); } void Gfx::opShFill(Object args[], int numArgs) { GfxShading *shading; GfxState *savedState; double xMin, yMin, xMax, yMax; if (!ocState) { return; } if (!(shading = res->lookupShading(args[0].getName()))) { return; } // save current graphics state savedState = saveStateStack(); // clip to bbox if (shading->getHasBBox()) { shading->getBBox(&xMin, &yMin, &xMax, &yMax); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); state->clip(); out->clip(state); state->clearPath(); } // set the color space state->setFillColorSpace(shading->getColorSpace()->copy()); out->updateFillColorSpace(state); #if 1 //~tmp: turn off anti-aliasing temporarily out->setInShading(gTrue); #endif // do shading type-specific operations switch (shading->getType()) { case 1: doFunctionShFill((GfxFunctionShading *)shading); break; case 2: doAxialShFill((GfxAxialShading *)shading); break; case 3: doRadialShFill((GfxRadialShading *)shading); break; case 4: case 5: doGouraudTriangleShFill((GfxGouraudTriangleShading *)shading); break; case 6: case 7: doPatchMeshShFill((GfxPatchMeshShading *)shading); break; } #if 1 //~tmp: turn off anti-aliasing temporarily out->setInShading(gFalse); #endif // restore graphics state restoreStateStack(savedState); delete shading; } void Gfx::doFunctionShFill(GfxFunctionShading *shading) { double x0, y0, x1, y1; GfxColor colors[4]; if (out->useShadedFills() && out->functionShadedFill(state, shading)) { return; } shading->getDomain(&x0, &y0, &x1, &y1); shading->getColor(x0, y0, &colors[0]); shading->getColor(x0, y1, &colors[1]); shading->getColor(x1, y0, &colors[2]); shading->getColor(x1, y1, &colors[3]); doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0); } void Gfx::doFunctionShFill1(GfxFunctionShading *shading, double x0, double y0, double x1, double y1, GfxColor *colors, int depth) { GfxColor fillColor; GfxColor color0M, color1M, colorM0, colorM1, colorMM; GfxColor colors2[4]; double *matrix; double xM, yM; int nComps, i, j; nComps = shading->getColorSpace()->getNComps(); matrix = shading->getMatrix(); // compare the four corner colors for (i = 0; i < 4; ++i) { for (j = 0; j < nComps; ++j) { if (abs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) { break; } } if (j < nComps) { break; } } // center of the rectangle xM = 0.5 * (x0 + x1); yM = 0.5 * (y0 + y1); // the four corner colors are close (or we hit the recursive limit) // -- fill the rectangle; but require at least one subdivision // (depth==0) to avoid problems when the four outer corners of the // shaded region are the same color if ((i == 4 && depth > 0) || depth == functionMaxDepth) { // use the center color shading->getColor(xM, yM, &fillColor); state->setFillColor(&fillColor); out->updateFillColor(state); // fill the rectangle state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4], x0 * matrix[1] + y0 * matrix[3] + matrix[5]); state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4], x1 * matrix[1] + y0 * matrix[3] + matrix[5]); state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4], x1 * matrix[1] + y1 * matrix[3] + matrix[5]); state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4], x0 * matrix[1] + y1 * matrix[3] + matrix[5]); state->closePath(); out->fill(state); state->clearPath(); // the four corner colors are not close enough -- subdivide the // rectangle } else { // colors[0] colorM0 colors[2] // (x0,y0) (xM,y0) (x1,y0) // +----------+----------+ // | | | // | UL | UR | // color0M | colorMM | color1M // (x0,yM) +----------+----------+ (x1,yM) // | (xM,yM) | // | LL | LR | // | | | // +----------+----------+ // colors[1] colorM1 colors[3] // (x0,y1) (xM,y1) (x1,y1) shading->getColor(x0, yM, &color0M); shading->getColor(x1, yM, &color1M); shading->getColor(xM, y0, &colorM0); shading->getColor(xM, y1, &colorM1); shading->getColor(xM, yM, &colorMM); // upper-left sub-rectangle colors2[0] = colors[0]; colors2[1] = color0M; colors2[2] = colorM0; colors2[3] = colorMM; doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1); // lower-left sub-rectangle colors2[0] = color0M; colors2[1] = colors[1]; colors2[2] = colorMM; colors2[3] = colorM1; doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1); // upper-right sub-rectangle colors2[0] = colorM0; colors2[1] = colorMM; colors2[2] = colors[2]; colors2[3] = color1M; doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1); // lower-right sub-rectangle colors2[0] = colorMM; colors2[1] = colorM1; colors2[2] = color1M; colors2[3] = colors[3]; doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1); } } void Gfx::doAxialShFill(GfxAxialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, x1, y1; double dx, dy, mul; GBool dxdyZero, horiz; double tMin, tMax, t, tx, ty; double sMin, sMax, tmp; double ux0, uy0, ux1, uy1, vx0, vy0, vx1, vy1; double t0, t1, tt; double ta[axialMaxSplits + 1]; int next[axialMaxSplits + 1]; GfxColor color0, color1; int nComps; int i, j, k; if (out->useShadedFills() && out->axialShadedFill(state, shading)) { return; } // get the clip region bbox state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); // compute min and max t values, based on the four corners of the // clip region bbox shading->getCoords(&x0, &y0, &x1, &y1); dx = x1 - x0; dy = y1 - y0; dxdyZero = fabs(dx) < 0.01 && fabs(dy) < 0.01; horiz = fabs(dy) < fabs(dx); if (dxdyZero) { tMin = tMax = 0; } else { mul = 1 / (dx * dx + dy * dy); tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } if (tMin < 0 && !shading->getExtend0()) { tMin = 0; } if (tMax > 1 && !shading->getExtend1()) { tMax = 1; } } // get the function domain t0 = shading->getDomain0(); t1 = shading->getDomain1(); // Traverse the t axis and do the shading. // // For each point (tx, ty) on the t axis, consider a line through // that point perpendicular to the t axis: // // x(s) = tx + s * -dy --> s = (x - tx) / -dy // y(s) = ty + s * dx --> s = (y - ty) / dx // // Then look at the intersection of this line with the bounding box // (xMin, yMin, xMax, yMax). For -1 < |dy/dx| < 1, look at the // intersection with yMin, yMax: // // s0 = (yMin - ty) / dx // s1 = (yMax - ty) / dx // // else look at the intersection with xMin, xMax: // // s0 = (xMin - tx) / -dy // s1 = (xMax - tx) / -dy // // Each filled polygon is bounded by two of these line segments // perpdendicular to the t axis. // // The t axis is bisected into smaller regions until the color // difference across a region is small enough, and then the region // is painted with a single color. // set up nComps = shading->getColorSpace()->getNComps(); ta[0] = tMin; next[0] = axialMaxSplits; ta[axialMaxSplits] = tMax; // compute the color at t = tMin if (tMin < 0) { tt = t0; } else if (tMin > 1) { tt = t1; } else { tt = t0 + (t1 - t0) * tMin; } shading->getColor(tt, &color0); // compute the coordinates of the point on the t axis at t = tMin; // then compute the intersection of the perpendicular line with the // bounding box tx = x0 + tMin * dx; ty = y0 + tMin * dy; if (dxdyZero) { sMin = sMax = 0; } else { if (horiz) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; } else { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; } if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } } ux0 = tx - sMin * dy; uy0 = ty + sMin * dx; vx0 = tx - sMax * dy; vy0 = ty + sMax * dx; i = 0; while (i < axialMaxSplits) { // bisect until color difference is small enough or we hit the // bisection limit j = next[i]; while (j > i + 1) { if (ta[j] < 0) { tt = t0; } else if (ta[j] > 1) { tt = t1; } else { tt = t0 + (t1 - t0) * ta[j]; } // require at least two splits (to avoid problems where the // color doesn't change smoothly along the t axis) if (j - i <= axialMaxSplits / 4) { shading->getColor(tt, &color1); for (k = 0; k < nComps; ++k) { if (abs(color1.c[k] - color0.c[k]) > axialColorDelta) { break; } } if (k == nComps) { break; } } k = (i + j) / 2; ta[k] = 0.5 * (ta[i] + ta[j]); next[i] = k; next[k] = j; j = k; } // use the average of the colors of the two sides of the region for (k = 0; k < nComps; ++k) { color0.c[k] = (color0.c[k] + color1.c[k]) / 2; } // compute the coordinates of the point on the t axis; then // compute the intersection of the perpendicular line with the // bounding box tx = x0 + ta[j] * dx; ty = y0 + ta[j] * dy; if (dxdyZero) { sMin = sMax = 0; } else { if (horiz) { sMin = (yMin - ty) / dx; sMax = (yMax - ty) / dx; } else { sMin = (xMin - tx) / -dy; sMax = (xMax - tx) / -dy; } if (sMin > sMax) { tmp = sMin; sMin = sMax; sMax = tmp; } } ux1 = tx - sMin * dy; uy1 = ty + sMin * dx; vx1 = tx - sMax * dy; vy1 = ty + sMax * dx; // set the color state->setFillColor(&color0); out->updateFillColor(state); // fill the region state->moveTo(ux0, uy0); state->lineTo(vx0, vy0); state->lineTo(vx1, vy1); state->lineTo(ux1, uy1); state->closePath(); out->fill(state); state->clearPath(); // set up for next region ux0 = ux1; uy0 = uy1; vx0 = vx1; vy0 = vy1; color0 = color1; i = next[i]; } } void Gfx::doRadialShFill(GfxRadialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, r0, x1, y1, r1, t0, t1; int nComps; GfxColor colorA, colorB; double xa, ya, xb, yb, ra, rb; double ta, tb, sa, sb; double sz, sMin, sMax, h; double sLeft, sRight, sTop, sBottom, sZero, sDiag; GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero; GBool haveSMin, haveSMax; GBool enclosed; int ia, ib, k, n; double *ctm; double theta, alpha, angle, t; if (out->useShadedFills() && out->radialShadedFill(state, shading)) { return; } // get the shading info shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); t0 = shading->getDomain0(); t1 = shading->getDomain1(); nComps = shading->getColorSpace()->getNComps(); // Compute the point at which r(s) = 0; check for the enclosed // circles case; and compute the angles for the tangent lines. h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); if (h == 0) { enclosed = gTrue; theta = 0; // make gcc happy sz = 0; // make gcc happy } else if (r1 - r0 == 0) { enclosed = gFalse; theta = 0; sz = 0; // make gcc happy } else if (fabs(r1 - r0) >= h) { enclosed = gTrue; theta = 0; // make gcc happy sz = 0; // make gcc happy } else { enclosed = gFalse; sz = -r0 / (r1 - r0); theta = asin((r1 - r0) / h); } if (enclosed) { alpha = 0; } else { alpha = atan2(y1 - y0, x1 - x0); } // compute the (possibly extended) s range state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); if (enclosed) { sMin = 0; sMax = 1; } else { // solve x(sLeft) + r(sLeft) = xMin if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) { sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); } else { sLeft = 0; // make gcc happy } // solve x(sRight) - r(sRight) = xMax if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) { sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); } else { sRight = 0; // make gcc happy } // solve y(sBottom) + r(sBottom) = yMin if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) { sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); } else { sBottom = 0; // make gcc happy } // solve y(sTop) - r(sTop) = yMax if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) { sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); } else { sTop = 0; // make gcc happy } // solve r(sZero) = 0 if ((haveSZero = fabs(r1 - r0) > 0.000001)) { sZero = -r0 / (r1 - r0); } else { sZero = 0; // make gcc happy } // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2) if (haveSZero) { sDiag = (sqrt((xMax - xMin) * (xMax - xMin) + (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); } else { sDiag = 0; // make gcc happy } // compute sMin if (shading->getExtend0()) { sMin = 0; haveSMin = gFalse; if (x0 < x1 && haveSLeft && sLeft < 0) { sMin = sLeft; haveSMin = gTrue; } else if (x0 > x1 && haveSRight && sRight < 0) { sMin = sRight; haveSMin = gTrue; } if (y0 < y1 && haveSBottom && sBottom < 0) { if (!haveSMin || sBottom > sMin) { sMin = sBottom; haveSMin = gTrue; } } else if (y0 > y1 && haveSTop && sTop < 0) { if (!haveSMin || sTop > sMin) { sMin = sTop; haveSMin = gTrue; } } if (haveSZero && sZero < 0) { if (!haveSMin || sZero > sMin) { sMin = sZero; } } } else { sMin = 0; } // compute sMax if (shading->getExtend1()) { sMax = 1; haveSMax = gFalse; if (x1 < x0 && haveSLeft && sLeft > 1) { sMax = sLeft; haveSMax = gTrue; } else if (x1 > x0 && haveSRight && sRight > 1) { sMax = sRight; haveSMax = gTrue; } if (y1 < y0 && haveSBottom && sBottom > 1) { if (!haveSMax || sBottom < sMax) { sMax = sBottom; haveSMax = gTrue; } } else if (y1 > y0 && haveSTop && sTop > 1) { if (!haveSMax || sTop < sMax) { sMax = sTop; haveSMax = gTrue; } } if (haveSZero && sDiag > 1) { if (!haveSMax || sDiag < sMax) { sMax = sDiag; } } } else { sMax = 1; } } // compute the number of steps into which circles must be divided to // achieve a curve flatness of 0.1 pixel in device space for the // largest circle (note that "device space" is 72 dpi when generating // PostScript, hence the relatively small 0.1 pixel accuracy) ctm = state->getCTM(); t = fabs(ctm[0]); if (fabs(ctm[1]) > t) { t = fabs(ctm[1]); } if (fabs(ctm[2]) > t) { t = fabs(ctm[2]); } if (fabs(ctm[3]) > t) { t = fabs(ctm[3]); } if (r0 > r1) { t *= r0; } else { t *= r1; } if (t < 1) { n = 3; } else { n = (int)(M_PI / acos(1 - 0.1 / t)); if (n < 3) { n = 3; } else if (n > 200) { n = 200; } } // setup for the start circle ia = 0; sa = sMin; ta = t0 + sa * (t1 - t0); xa = x0 + sa * (x1 - x0); ya = y0 + sa * (y1 - y0); ra = r0 + sa * (r1 - r0); if (ta < t0) { shading->getColor(t0, &colorA); } else if (ta > t1) { shading->getColor(t1, &colorA); } else { shading->getColor(ta, &colorA); } // fill the circles while (ia < radialMaxSplits) { // go as far along the t axis (toward t1) as we can, such that the // color difference is within the tolerance (radialColorDelta) -- // this uses bisection (between the current value, t, and t1), // limited to radialMaxSplits points along the t axis; require at // least one split to avoid problems when the innermost and // outermost colors are the same ib = radialMaxSplits; sb = sMax; tb = t0 + sb * (t1 - t0); if (tb < t0) { shading->getColor(t0, &colorB); } else if (tb > t1) { shading->getColor(t1, &colorB); } else { shading->getColor(tb, &colorB); } while (ib - ia > 1) { for (k = 0; k < nComps; ++k) { if (abs(colorB.c[k] - colorA.c[k]) > radialColorDelta) { break; } } if (k == nComps && ib < radialMaxSplits) { break; } ib = (ia + ib) / 2; sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin); tb = t0 + sb * (t1 - t0); if (tb < t0) { shading->getColor(t0, &colorB); } else if (tb > t1) { shading->getColor(t1, &colorB); } else { shading->getColor(tb, &colorB); } } // compute center and radius of the circle xb = x0 + sb * (x1 - x0); yb = y0 + sb * (y1 - y0); rb = r0 + sb * (r1 - r0); // use the average of the colors at the two circles for (k = 0; k < nComps; ++k) { colorA.c[k] = (colorA.c[k] + colorB.c[k]) / 2; } state->setFillColor(&colorA); out->updateFillColor(state); if (enclosed) { // construct path for first circle (counterclockwise) state->moveTo(xa + ra, ya); for (k = 1; k < n; ++k) { angle = ((double)k / (double)n) * 2 * M_PI; state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); // construct and append path for second circle (clockwise) state->moveTo(xb + rb, yb); for (k = 1; k < n; ++k) { angle = -((double)k / (double)n) * 2 * M_PI; state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); } state->closePath(); } else { // construct the first subpath (clockwise) state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), ya + ra * sin(alpha + theta + 0.5 * M_PI)); for (k = 0; k < n; ++k) { angle = alpha + theta + 0.5 * M_PI - ((double)k / (double)n) * (2 * theta + M_PI); state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); } for (k = 0; k < n; ++k) { angle = alpha - theta - 0.5 * M_PI + ((double)k / (double)n) * (2 * theta - M_PI); state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); // construct the second subpath (counterclockwise) state->moveTo(xa + ra * cos(alpha + theta + 0.5 * M_PI), ya + ra * sin(alpha + theta + 0.5 * M_PI)); for (k = 0; k < n; ++k) { angle = alpha + theta + 0.5 * M_PI + ((double)k / (double)n) * (-2 * theta + M_PI); state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle)); } for (k = 0; k < n; ++k) { angle = alpha - theta - 0.5 * M_PI + ((double)k / (double)n) * (2 * theta + M_PI); state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); } // fill the path out->fill(state); state->clearPath(); // step to the next value of t ia = ib; sa = sb; ta = tb; xa = xb; ya = yb; ra = rb; colorA = colorB; } if (enclosed) { // extend the smaller circle if ((shading->getExtend0() && r0 <= r1) || (shading->getExtend1() && r1 < r0)) { if (r0 <= r1) { ta = t0; ra = r0; xa = x0; ya = y0; } else { ta = t1; ra = r1; xa = x1; ya = y1; } shading->getColor(ta, &colorA); state->setFillColor(&colorA); out->updateFillColor(state); state->moveTo(xa + ra, ya); for (k = 1; k < n; ++k) { angle = ((double)k / (double)n) * 2 * M_PI; state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); out->fill(state); state->clearPath(); } // extend the larger circle if ((shading->getExtend0() && r0 > r1) || (shading->getExtend1() && r1 >= r0)) { if (r0 > r1) { ta = t0; ra = r0; xa = x0; ya = y0; } else { ta = t1; ra = r1; xa = x1; ya = y1; } shading->getColor(ta, &colorA); state->setFillColor(&colorA); out->updateFillColor(state); state->moveTo(xMin, yMin); state->lineTo(xMin, yMax); state->lineTo(xMax, yMax); state->lineTo(xMax, yMin); state->closePath(); state->moveTo(xa + ra, ya); for (k = 1; k < n; ++k) { angle = ((double)k / (double)n) * 2 * M_PI; state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle)); } state->closePath(); out->fill(state); state->clearPath(); } } } void Gfx::doGouraudTriangleShFill(GfxGouraudTriangleShading *shading) { double x0, y0, x1, y1, x2, y2; GfxColor color0, color1, color2; int i; for (i = 0; i < shading->getNTriangles(); ++i) { shading->getTriangle(i, &x0, &y0, &color0, &x1, &y1, &color1, &x2, &y2, &color2); gouraudFillTriangle(x0, y0, &color0, x1, y1, &color1, x2, y2, &color2, shading->getColorSpace()->getNComps(), 0); } } void Gfx::gouraudFillTriangle(double x0, double y0, GfxColor *color0, double x1, double y1, GfxColor *color1, double x2, double y2, GfxColor *color2, int nComps, int depth) { double x01, y01, x12, y12, x20, y20; GfxColor color01, color12, color20; int i; for (i = 0; i < nComps; ++i) { if (abs(color0->c[i] - color1->c[i]) > gouraudColorDelta || abs(color1->c[i] - color2->c[i]) > gouraudColorDelta) { break; } } if (i == nComps || depth == gouraudMaxDepth) { state->setFillColor(color0); out->updateFillColor(state); state->moveTo(x0, y0); state->lineTo(x1, y1); state->lineTo(x2, y2); state->closePath(); out->fill(state); state->clearPath(); } else { x01 = 0.5 * (x0 + x1); y01 = 0.5 * (y0 + y1); x12 = 0.5 * (x1 + x2); y12 = 0.5 * (y1 + y2); x20 = 0.5 * (x2 + x0); y20 = 0.5 * (y2 + y0); //~ if the shading has a Function, this should interpolate on the //~ function parameter, not on the color components for (i = 0; i < nComps; ++i) { color01.c[i] = (color0->c[i] + color1->c[i]) / 2; color12.c[i] = (color1->c[i] + color2->c[i]) / 2; color20.c[i] = (color2->c[i] + color0->c[i]) / 2; } gouraudFillTriangle(x0, y0, color0, x01, y01, &color01, x20, y20, &color20, nComps, depth + 1); gouraudFillTriangle(x01, y01, &color01, x1, y1, color1, x12, y12, &color12, nComps, depth + 1); gouraudFillTriangle(x01, y01, &color01, x12, y12, &color12, x20, y20, &color20, nComps, depth + 1); gouraudFillTriangle(x20, y20, &color20, x12, y12, &color12, x2, y2, color2, nComps, depth + 1); } } void Gfx::doPatchMeshShFill(GfxPatchMeshShading *shading) { int start, i; if (shading->getNPatches() > 128) { start = 3; } else if (shading->getNPatches() > 64) { start = 2; } else if (shading->getNPatches() > 16) { start = 1; } else { start = 0; } for (i = 0; i < shading->getNPatches(); ++i) { fillPatch(shading->getPatch(i), shading->getColorSpace()->getNComps(), start); } } void Gfx::fillPatch(GfxPatch *patch, int nComps, int depth) { GfxPatch patch00, patch01, patch10, patch11; double xx[4][8], yy[4][8]; double xxm, yym; int i; for (i = 0; i < nComps; ++i) { if (abs(patch->color[0][0].c[i] - patch->color[0][1].c[i]) > patchColorDelta || abs(patch->color[0][1].c[i] - patch->color[1][1].c[i]) > patchColorDelta || abs(patch->color[1][1].c[i] - patch->color[1][0].c[i]) > patchColorDelta || abs(patch->color[1][0].c[i] - patch->color[0][0].c[i]) > patchColorDelta) { break; } } if (i == nComps || depth == patchMaxDepth) { state->setFillColor(&patch->color[0][0]); out->updateFillColor(state); state->moveTo(patch->x[0][0], patch->y[0][0]); state->curveTo(patch->x[0][1], patch->y[0][1], patch->x[0][2], patch->y[0][2], patch->x[0][3], patch->y[0][3]); state->curveTo(patch->x[1][3], patch->y[1][3], patch->x[2][3], patch->y[2][3], patch->x[3][3], patch->y[3][3]); state->curveTo(patch->x[3][2], patch->y[3][2], patch->x[3][1], patch->y[3][1], patch->x[3][0], patch->y[3][0]); state->curveTo(patch->x[2][0], patch->y[2][0], patch->x[1][0], patch->y[1][0], patch->x[0][0], patch->y[0][0]); state->closePath(); out->fill(state); state->clearPath(); } else { for (i = 0; i < 4; ++i) { xx[i][0] = patch->x[i][0]; yy[i][0] = patch->y[i][0]; xx[i][1] = 0.5 * (patch->x[i][0] + patch->x[i][1]); yy[i][1] = 0.5 * (patch->y[i][0] + patch->y[i][1]); xxm = 0.5 * (patch->x[i][1] + patch->x[i][2]); yym = 0.5 * (patch->y[i][1] + patch->y[i][2]); xx[i][6] = 0.5 * (patch->x[i][2] + patch->x[i][3]); yy[i][6] = 0.5 * (patch->y[i][2] + patch->y[i][3]); xx[i][2] = 0.5 * (xx[i][1] + xxm); yy[i][2] = 0.5 * (yy[i][1] + yym); xx[i][5] = 0.5 * (xxm + xx[i][6]); yy[i][5] = 0.5 * (yym + yy[i][6]); xx[i][3] = xx[i][4] = 0.5 * (xx[i][2] + xx[i][5]); yy[i][3] = yy[i][4] = 0.5 * (yy[i][2] + yy[i][5]); xx[i][7] = patch->x[i][3]; yy[i][7] = patch->y[i][3]; } for (i = 0; i < 4; ++i) { patch00.x[0][i] = xx[0][i]; patch00.y[0][i] = yy[0][i]; patch00.x[1][i] = 0.5 * (xx[0][i] + xx[1][i]); patch00.y[1][i] = 0.5 * (yy[0][i] + yy[1][i]); xxm = 0.5 * (xx[1][i] + xx[2][i]); yym = 0.5 * (yy[1][i] + yy[2][i]); patch10.x[2][i] = 0.5 * (xx[2][i] + xx[3][i]); patch10.y[2][i] = 0.5 * (yy[2][i] + yy[3][i]); patch00.x[2][i] = 0.5 * (patch00.x[1][i] + xxm); patch00.y[2][i] = 0.5 * (patch00.y[1][i] + yym); patch10.x[1][i] = 0.5 * (xxm + patch10.x[2][i]); patch10.y[1][i] = 0.5 * (yym + patch10.y[2][i]); patch00.x[3][i] = 0.5 * (patch00.x[2][i] + patch10.x[1][i]); patch00.y[3][i] = 0.5 * (patch00.y[2][i] + patch10.y[1][i]); patch10.x[0][i] = patch00.x[3][i]; patch10.y[0][i] = patch00.y[3][i]; patch10.x[3][i] = xx[3][i]; patch10.y[3][i] = yy[3][i]; } for (i = 4; i < 8; ++i) { patch01.x[0][i-4] = xx[0][i]; patch01.y[0][i-4] = yy[0][i]; patch01.x[1][i-4] = 0.5 * (xx[0][i] + xx[1][i]); patch01.y[1][i-4] = 0.5 * (yy[0][i] + yy[1][i]); xxm = 0.5 * (xx[1][i] + xx[2][i]); yym = 0.5 * (yy[1][i] + yy[2][i]); patch11.x[2][i-4] = 0.5 * (xx[2][i] + xx[3][i]); patch11.y[2][i-4] = 0.5 * (yy[2][i] + yy[3][i]); patch01.x[2][i-4] = 0.5 * (patch01.x[1][i-4] + xxm); patch01.y[2][i-4] = 0.5 * (patch01.y[1][i-4] + yym); patch11.x[1][i-4] = 0.5 * (xxm + patch11.x[2][i-4]); patch11.y[1][i-4] = 0.5 * (yym + patch11.y[2][i-4]); patch01.x[3][i-4] = 0.5 * (patch01.x[2][i-4] + patch11.x[1][i-4]); patch01.y[3][i-4] = 0.5 * (patch01.y[2][i-4] + patch11.y[1][i-4]); patch11.x[0][i-4] = patch01.x[3][i-4]; patch11.y[0][i-4] = patch01.y[3][i-4]; patch11.x[3][i-4] = xx[3][i]; patch11.y[3][i-4] = yy[3][i]; } //~ if the shading has a Function, this should interpolate on the //~ function parameter, not on the color components for (i = 0; i < nComps; ++i) { patch00.color[0][0].c[i] = patch->color[0][0].c[i]; patch00.color[0][1].c[i] = (patch->color[0][0].c[i] + patch->color[0][1].c[i]) / 2; patch01.color[0][0].c[i] = patch00.color[0][1].c[i]; patch01.color[0][1].c[i] = patch->color[0][1].c[i]; patch01.color[1][1].c[i] = (patch->color[0][1].c[i] + patch->color[1][1].c[i]) / 2; patch11.color[0][1].c[i] = patch01.color[1][1].c[i]; patch11.color[1][1].c[i] = patch->color[1][1].c[i]; patch11.color[1][0].c[i] = (patch->color[1][1].c[i] + patch->color[1][0].c[i]) / 2; patch10.color[1][1].c[i] = patch11.color[1][0].c[i]; patch10.color[1][0].c[i] = patch->color[1][0].c[i]; patch10.color[0][0].c[i] = (patch->color[1][0].c[i] + patch->color[0][0].c[i]) / 2; patch00.color[1][0].c[i] = patch10.color[0][0].c[i]; patch00.color[1][1].c[i] = (patch00.color[1][0].c[i] + patch01.color[1][1].c[i]) / 2; patch01.color[1][0].c[i] = patch00.color[1][1].c[i]; patch11.color[0][0].c[i] = patch00.color[1][1].c[i]; patch10.color[0][1].c[i] = patch00.color[1][1].c[i]; } fillPatch(&patch00, nComps, depth + 1); fillPatch(&patch10, nComps, depth + 1); fillPatch(&patch01, nComps, depth + 1); fillPatch(&patch11, nComps, depth + 1); } } void Gfx::doEndPath() { if (state->isCurPt() && clip != clipNone) { state->clip(); if (clip == clipNormal) { out->clip(state); } else { out->eoClip(state); } } clip = clipNone; state->clearPath(); } //------------------------------------------------------------------------ // path clipping operators //------------------------------------------------------------------------ void Gfx::opClip(Object args[], int numArgs) { clip = clipNormal; } void Gfx::opEOClip(Object args[], int numArgs) { clip = clipEO; } //------------------------------------------------------------------------ // text object operators //------------------------------------------------------------------------ void Gfx::opBeginText(Object args[], int numArgs) { state->setTextMat(1, 0, 0, 1, 0, 0); state->textMoveTo(0, 0); out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; textClipBBoxEmpty = gTrue; } void Gfx::opEndText(Object args[], int numArgs) { out->endTextObject(state); } //------------------------------------------------------------------------ // text state operators //------------------------------------------------------------------------ void Gfx::opSetCharSpacing(Object args[], int numArgs) { state->setCharSpace(args[0].getNum()); out->updateCharSpace(state); } void Gfx::opSetFont(Object args[], int numArgs) { GfxFont *font; if (!(font = res->lookupFont(args[0].getName()))) { return; } if (printCommands) { printf(" font: tag=%s name='%s' %g\n", font->getTag()->getCString(), font->getName() ? font->getName()->getCString() : "???", args[1].getNum()); fflush(stdout); } state->setFont(font, args[1].getNum()); fontChanged = gTrue; } void Gfx::opSetTextLeading(Object args[], int numArgs) { state->setLeading(args[0].getNum()); } void Gfx::opSetTextRender(Object args[], int numArgs) { state->setRender(args[0].getInt()); out->updateRender(state); } void Gfx::opSetTextRise(Object args[], int numArgs) { state->setRise(args[0].getNum()); out->updateRise(state); } void Gfx::opSetWordSpacing(Object args[], int numArgs) { state->setWordSpace(args[0].getNum()); out->updateWordSpace(state); } void Gfx::opSetHorizScaling(Object args[], int numArgs) { state->setHorizScaling(args[0].getNum()); out->updateHorizScaling(state); fontChanged = gTrue; } //------------------------------------------------------------------------ // text positioning operators //------------------------------------------------------------------------ void Gfx::opTextMove(Object args[], int numArgs) { double tx, ty; tx = state->getLineX() + args[0].getNum(); ty = state->getLineY() + args[1].getNum(); state->textMoveTo(tx, ty); out->updateTextPos(state); } void Gfx::opTextMoveSet(Object args[], int numArgs) { double tx, ty; tx = state->getLineX() + args[0].getNum(); ty = args[1].getNum(); state->setLeading(-ty); ty += state->getLineY(); state->textMoveTo(tx, ty); out->updateTextPos(state); } void Gfx::opSetTextMatrix(Object args[], int numArgs) { state->setTextMat(args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); state->textMoveTo(0, 0); out->updateTextMat(state); out->updateTextPos(state); fontChanged = gTrue; } void Gfx::opTextNextLine(Object args[], int numArgs) { double tx, ty; tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateTextPos(state); } //------------------------------------------------------------------------ // text string operators //------------------------------------------------------------------------ void Gfx::opShowText(Object args[], int numArgs) { if (!state->getFont()) { error(errSyntaxError, getPos(), "No font in show"); return; } if (fontChanged) { out->updateFont(state); fontChanged = gFalse; } if (ocState) { out->beginStringOp(state); doShowText(args[0].getString()); out->endStringOp(state); } else { doIncCharCount(args[0].getString()); } } void Gfx::opMoveShowText(Object args[], int numArgs) { double tx, ty; if (!state->getFont()) { error(errSyntaxError, getPos(), "No font in move/show"); return; } if (fontChanged) { out->updateFont(state); fontChanged = gFalse; } tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateTextPos(state); if (ocState) { out->beginStringOp(state); doShowText(args[0].getString()); out->endStringOp(state); } else { doIncCharCount(args[0].getString()); } } void Gfx::opMoveSetShowText(Object args[], int numArgs) { double tx, ty; if (!state->getFont()) { error(errSyntaxError, getPos(), "No font in move/set/show"); return; } if (fontChanged) { out->updateFont(state); fontChanged = gFalse; } state->setWordSpace(args[0].getNum()); state->setCharSpace(args[1].getNum()); tx = state->getLineX(); ty = state->getLineY() - state->getLeading(); state->textMoveTo(tx, ty); out->updateWordSpace(state); out->updateCharSpace(state); out->updateTextPos(state); if (ocState) { out->beginStringOp(state); doShowText(args[2].getString()); out->endStringOp(state); } else { doIncCharCount(args[2].getString()); } } void Gfx::opShowSpaceText(Object args[], int numArgs) { Array *a; Object obj; int wMode; int i; if (!state->getFont()) { error(errSyntaxError, getPos(), "No font in show/space"); return; } if (fontChanged) { out->updateFont(state); fontChanged = gFalse; } if (ocState) { out->beginStringOp(state); wMode = state->getFont()->getWMode(); a = args[0].getArray(); for (i = 0; i < a->getLength(); ++i) { a->get(i, &obj); if (obj.isNum()) { if (wMode) { state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize()); } else { state->textShift(-obj.getNum() * 0.001 * state->getFontSize() * state->getHorizScaling(), 0); } out->updateTextShift(state, obj.getNum()); } else if (obj.isString()) { doShowText(obj.getString()); } else { error(errSyntaxError, getPos(), "Element of show/space array must be number or string"); } obj.free(); } out->endStringOp(state); } else { a = args[0].getArray(); for (i = 0; i < a->getLength(); ++i) { a->get(i, &obj); if (obj.isString()) { doIncCharCount(obj.getString()); } obj.free(); } } } void Gfx::doShowText(GString *s) { GfxFont *font; int wMode; double riseX, riseY; CharCode code; Unicode u[8]; double x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy, ddx, ddy; double originX, originY, tOriginX, tOriginY; double x0, y0, x1, y1; double oldCTM[6], newCTM[6]; double *mat; Object charProc; Dict *resDict; Parser *oldParser; GfxState *savedState; char *p; int render; GBool patternFill; int len, n, uLen, nChars, nSpaces, i; font = state->getFont(); wMode = font->getWMode(); if (out->useDrawChar()) { out->beginString(state, s); } // if we're doing a pattern fill, set up clipping render = state->getRender(); if (!(render & 1) && state->getFillColorSpace()->getMode() == csPattern) { patternFill = gTrue; saveState(); // disable fill, enable clipping, leave stroke unchanged if ((render ^ (render >> 1)) & 1) { render = 5; } else { render = 7; } state->setRender(render); out->updateRender(state); } else { patternFill = gFalse; } state->textTransformDelta(0, state->getRise(), &riseX, &riseY); x0 = state->getCurX() + riseX; y0 = state->getCurY() + riseY; // handle a Type 3 char if (font->getType() == fontType3 && out->interpretType3Chars()) { mat = state->getCTM(); for (i = 0; i < 6; ++i) { oldCTM[i] = mat[i]; } mat = state->getTextMat(); newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2]; newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3]; newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2]; newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3]; mat = font->getFontMatrix(); newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2]; newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3]; newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; newCTM[0] *= state->getFontSize(); newCTM[1] *= state->getFontSize(); newCTM[2] *= state->getFontSize(); newCTM[3] *= state->getFontSize(); newCTM[0] *= state->getHorizScaling(); newCTM[2] *= state->getHorizScaling(); curX = state->getCurX(); curY = state->getCurY(); oldParser = parser; p = s->getCString(); len = s->getLength(); while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY); dx = dx * state->getFontSize() + state->getCharSpace(); if (n == 1 && *p == ' ') { dx += state->getWordSpace(); } dx *= state->getHorizScaling(); dy *= state->getFontSize(); state->textTransformDelta(dx, dy, &tdx, &tdy); state->transform(curX + riseX, curY + riseY, &x, &y); savedState = saveStateStack(); state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); //~ the CTM concat values here are wrong (but never used) out->updateCTM(state, 1, 0, 0, 1, 0, 0); state->transformDelta(dx, dy, &ddx, &ddy); if (!out->beginType3Char(state, curX + riseX, curY + riseY, ddx, ddy, code, u, uLen)) { ((Gfx8BitFont *)font)->getCharProc(code, &charProc); if ((resDict = ((Gfx8BitFont *)font)->getResources())) { pushResources(resDict); } if (charProc.isStream()) { display(&charProc, gFalse); } else { error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry"); } out->endType3Char(state); if (resDict) { popResources(); } charProc.free(); } restoreStateStack(savedState); curX += tdx; curY += tdy; state->moveTo(curX, curY); p += n; len -= n; } parser = oldParser; } else if (out->useDrawChar()) { p = s->getCString(); len = s->getLength(); while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY); if (wMode) { dx *= state->getFontSize(); dy = dy * state->getFontSize() + state->getCharSpace(); if (n == 1 && *p == ' ') { dy += state->getWordSpace(); } } else { dx = dx * state->getFontSize() + state->getCharSpace(); if (n == 1 && *p == ' ') { dx += state->getWordSpace(); } dx *= state->getHorizScaling(); dy *= state->getFontSize(); } state->textTransformDelta(dx, dy, &tdx, &tdy); originX *= state->getFontSize(); originY *= state->getFontSize(); state->textTransformDelta(originX, originY, &tOriginX, &tOriginY); out->drawChar(state, state->getCurX() + riseX, state->getCurY() + riseY, tdx, tdy, tOriginX, tOriginY, code, n, u, uLen); state->shift(tdx, tdy); p += n; len -= n; } } else { dx = dy = 0; p = s->getCString(); len = s->getLength(); nChars = nSpaces = 0; while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx2, &dy2, &originX, &originY); dx += dx2; dy += dy2; if (n == 1 && *p == ' ') { ++nSpaces; } ++nChars; p += n; len -= n; } if (wMode) { dx *= state->getFontSize(); dy = dy * state->getFontSize() + nChars * state->getCharSpace() + nSpaces * state->getWordSpace(); } else { dx = dx * state->getFontSize() + nChars * state->getCharSpace() + nSpaces * state->getWordSpace(); dx *= state->getHorizScaling(); dy *= state->getFontSize(); } state->textTransformDelta(dx, dy, &tdx, &tdy); out->drawString(state, s); state->shift(tdx, tdy); } if (out->useDrawChar()) { out->endString(state); } if (patternFill) { out->saveTextPos(state); // tell the OutputDev to do the clipping out->endTextObject(state); // set up a clipping bbox so doPatternText will work -- assume // that the text bounding box does not extend past the baseline in // any direction by more than twice the font size x1 = state->getCurX() + riseX; y1 = state->getCurY() + riseY; if (x0 > x1) { x = x0; x0 = x1; x1 = x; } if (y0 > y1) { y = y0; y0 = y1; y1 = y; } state->textTransformDelta(0, state->getFontSize(), &dx, &dy); state->textTransformDelta(state->getFontSize(), 0, &dx2, &dy2); dx = fabs(dx); dx2 = fabs(dx2); if (dx2 > dx) { dx = dx2; } dy = fabs(dy); dy2 = fabs(dy2); if (dy2 > dy) { dy = dy2; } state->clipToRect(x0 - 2 * dx, y0 - 2 * dy, x1 + 2 * dx, y1 + 2 * dy); // set render mode to fill-only state->setRender(0); out->updateRender(state); doPatternText(); restoreState(); out->restoreTextPos(state); } updateLevel += 10 * s->getLength(); } // NB: this is only called when ocState is false. void Gfx::doIncCharCount(GString *s) { if (out->needCharCount()) { out->incCharCount(s->getLength()); } } //------------------------------------------------------------------------ // XObject operators //------------------------------------------------------------------------ void Gfx::opXObject(Object args[], int numArgs) { char *name; Object obj1, obj2, obj3, refObj; #if OPI_SUPPORT Object opiDict; #endif if (!ocState && !out->needCharCount()) { return; } name = args[0].getName(); if (!res->lookupXObject(name, &obj1)) { return; } if (!obj1.isStream()) { error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name); obj1.free(); return; } #if OPI_SUPPORT obj1.streamGetDict()->lookup("OPI", &opiDict); if (opiDict.isDict()) { out->opiBegin(state, opiDict.getDict()); } #endif obj1.streamGetDict()->lookup("Subtype", &obj2); if (obj2.isName("Image")) { if (out->needNonText()) { res->lookupXObjectNF(name, &refObj); doImage(&refObj, obj1.getStream(), gFalse); refObj.free(); } } else if (obj2.isName("Form")) { res->lookupXObjectNF(name, &refObj); if (out->useDrawForm() && refObj.isRef()) { out->drawForm(refObj.getRef()); } else { doForm(&obj1); } refObj.free(); } else if (obj2.isName("PS")) { obj1.streamGetDict()->lookup("Level1", &obj3); out->psXObject(obj1.getStream(), obj3.isStream() ? obj3.getStream() : (Stream *)NULL); } else if (obj2.isName()) { error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName()); } else { error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type"); } obj2.free(); #if OPI_SUPPORT if (opiDict.isDict()) { out->opiEnd(state, opiDict.getDict()); } opiDict.free(); #endif obj1.free(); } void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) { Dict *dict, *maskDict; int width, height; int bits, maskBits; StreamColorSpaceMode csMode; GBool mask; GBool invert; GfxColorSpace *colorSpace, *maskColorSpace; GfxImageColorMap *colorMap, *maskColorMap; Object maskObj, smaskObj; GBool haveColorKeyMask, haveExplicitMask, haveSoftMask; int maskColors[2*gfxColorMaxComps]; int maskWidth, maskHeight; GBool maskInvert; Stream *maskStr; Object obj1, obj2; int i, n; // get info from the stream bits = 0; csMode = streamCSNone; str->getImageParams(&bits, &csMode); // get stream dict dict = str->getDict(); // get size dict->lookup("Width", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("W", &obj1); } if (!obj1.isInt()) { goto err2; } width = obj1.getInt(); obj1.free(); if (width <= 0) { goto err1; } dict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("H", &obj1); } if (!obj1.isInt()) { goto err2; } height = obj1.getInt(); obj1.free(); if (height <= 0) { goto err1; } // image or mask? dict->lookup("ImageMask", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("IM", &obj1); } mask = gFalse; if (obj1.isBool()) mask = obj1.getBool(); else if (!obj1.isNull()) goto err2; obj1.free(); // bit depth if (bits == 0) { dict->lookup("BitsPerComponent", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("BPC", &obj1); } if (obj1.isInt()) { bits = obj1.getInt(); } else if (mask) { bits = 1; } else { goto err2; } obj1.free(); } // display a mask if (mask) { // check for inverted mask if (bits != 1) goto err1; invert = gFalse; dict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("D", &obj1); } if (obj1.isArray()) { obj1.arrayGet(0, &obj2); invert = obj2.isNum() && obj2.getNum() == 1; obj2.free(); } else if (!obj1.isNull()) { goto err2; } obj1.free(); // if drawing is disabled, skip over inline image data if (!ocState) { str->reset(); n = height * ((width + 7) / 8); for (i = 0; i < n; ++i) { str->getChar(); } str->close(); // draw it } else { if (state->getFillColorSpace()->getMode() == csPattern) { doPatternImageMask(ref, str, width, height, invert, inlineImg); } else { out->drawImageMask(state, ref, str, width, height, invert, inlineImg); } } } else { // get color space and color map dict->lookup("ColorSpace", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("CS", &obj1); } if (obj1.isName()) { res->lookupColorSpace(obj1.getName(), &obj2); if (!obj2.isNull()) { obj1.free(); obj1 = obj2; } else { obj2.free(); } } if (!obj1.isNull()) { colorSpace = GfxColorSpace::parse(&obj1); } else if (csMode == streamCSDeviceGray) { colorSpace = new GfxDeviceGrayColorSpace(); } else if (csMode == streamCSDeviceRGB) { colorSpace = new GfxDeviceRGBColorSpace(); } else if (csMode == streamCSDeviceCMYK) { colorSpace = new GfxDeviceCMYKColorSpace(); } else { colorSpace = NULL; } obj1.free(); if (!colorSpace) { goto err1; } dict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); dict->lookup("D", &obj1); } colorMap = new GfxImageColorMap(bits, &obj1, colorSpace); obj1.free(); if (!colorMap->isOk()) { delete colorMap; goto err1; } // get the mask haveColorKeyMask = haveExplicitMask = haveSoftMask = gFalse; maskStr = NULL; // make gcc happy maskWidth = maskHeight = 0; // make gcc happy maskInvert = gFalse; // make gcc happy maskColorMap = NULL; // make gcc happy dict->lookup("Mask", &maskObj); dict->lookup("SMask", &smaskObj); if (smaskObj.isStream()) { // soft mask if (inlineImg) { goto err1; } maskStr = smaskObj.getStream(); maskDict = smaskObj.streamGetDict(); maskDict->lookup("Width", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("W", &obj1); } if (!obj1.isInt()) { goto err2; } maskWidth = obj1.getInt(); obj1.free(); maskDict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("H", &obj1); } if (!obj1.isInt()) { goto err2; } maskHeight = obj1.getInt(); obj1.free(); maskDict->lookup("BitsPerComponent", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("BPC", &obj1); } if (!obj1.isInt()) { goto err2; } maskBits = obj1.getInt(); obj1.free(); maskDict->lookup("ColorSpace", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("CS", &obj1); } if (obj1.isName()) { res->lookupColorSpace(obj1.getName(), &obj2); if (!obj2.isNull()) { obj1.free(); obj1 = obj2; } else { obj2.free(); } } maskColorSpace = GfxColorSpace::parse(&obj1); obj1.free(); if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) { goto err1; } maskDict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("D", &obj1); } maskColorMap = new GfxImageColorMap(maskBits, &obj1, maskColorSpace); obj1.free(); if (!maskColorMap->isOk()) { delete maskColorMap; goto err1; } //~ handle the Matte entry haveSoftMask = gTrue; } else if (maskObj.isArray()) { // color key mask haveColorKeyMask = gTrue; for (i = 0; i+1 < maskObj.arrayGetLength() && i+1 < 2*gfxColorMaxComps; i += 2) { maskObj.arrayGet(i, &obj1); if (!obj1.isInt()) { obj1.free(); haveColorKeyMask = gFalse; break; } maskColors[i] = obj1.getInt(); obj1.free(); if (maskColors[i] < 0 || maskColors[i] >= (1 << bits)) { haveColorKeyMask = gFalse; break; } maskObj.arrayGet(i+1, &obj1); if (!obj1.isInt()) { obj1.free(); haveColorKeyMask = gFalse; break; } maskColors[i+1] = obj1.getInt(); obj1.free(); if (maskColors[i+1] < 0 || maskColors[i+1] >= (1 << bits) || maskColors[i] > maskColors[i+1]) { haveColorKeyMask = gFalse; break; } } } else if (maskObj.isStream()) { // explicit mask if (inlineImg) { goto err1; } maskStr = maskObj.getStream(); maskDict = maskObj.streamGetDict(); maskDict->lookup("Width", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("W", &obj1); } if (!obj1.isInt()) { goto err2; } maskWidth = obj1.getInt(); obj1.free(); maskDict->lookup("Height", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("H", &obj1); } if (!obj1.isInt()) { goto err2; } maskHeight = obj1.getInt(); obj1.free(); maskDict->lookup("ImageMask", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("IM", &obj1); } if (!obj1.isBool() || !obj1.getBool()) { goto err2; } obj1.free(); maskInvert = gFalse; maskDict->lookup("Decode", &obj1); if (obj1.isNull()) { obj1.free(); maskDict->lookup("D", &obj1); } if (obj1.isArray()) { obj1.arrayGet(0, &obj2); maskInvert = obj2.isNum() && obj2.getNum() == 1; obj2.free(); } else if (!obj1.isNull()) { goto err2; } obj1.free(); haveExplicitMask = gTrue; } // if drawing is disabled, skip over inline image data if (!ocState) { str->reset(); n = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); for (i = 0; i < n; ++i) { str->getChar(); } str->close(); // draw it } else { if (haveSoftMask) { out->drawSoftMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskColorMap); delete maskColorMap; } else if (haveExplicitMask) { out->drawMaskedImage(state, ref, str, width, height, colorMap, maskStr, maskWidth, maskHeight, maskInvert); } else { out->drawImage(state, ref, str, width, height, colorMap, haveColorKeyMask ? maskColors : (int *)NULL, inlineImg); } } delete colorMap; maskObj.free(); smaskObj.free(); } if ((i = width * height) > 1000) { i = 1000; } updateLevel += i; return; err2: obj1.free(); err1: error(errSyntaxError, getPos(), "Bad image parameters"); } void Gfx::doForm(Object *str) { Dict *dict; GBool transpGroup, isolated, knockout; GfxColorSpace *blendingColorSpace; Object matrixObj, bboxObj; double m[6], bbox[4]; Object resObj; Dict *resDict; GBool oc, ocSaved; Object obj1, obj2, obj3; int i; // check for excessive recursion if (formDepth > 100) { return; } // get stream dict dict = str->streamGetDict(); // check form type dict->lookup("FormType", &obj1); if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) { error(errSyntaxError, getPos(), "Unknown form type"); } obj1.free(); // check for optional content key ocSaved = ocState; dict->lookupNF("OC", &obj1); if (doc->getOptionalContent()->evalOCObject(&obj1, &oc) && !oc) { obj1.free(); if (out->needCharCount()) { ocState = gFalse; } else { return; } } obj1.free(); // get bounding box dict->lookup("BBox", &bboxObj); if (!bboxObj.isArray()) { bboxObj.free(); error(errSyntaxError, getPos(), "Bad form bounding box"); ocState = ocSaved; return; } for (i = 0; i < 4; ++i) { bboxObj.arrayGet(i, &obj1); bbox[i] = obj1.getNum(); obj1.free(); } bboxObj.free(); // get matrix dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); m[i] = obj1.getNum(); obj1.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0; } matrixObj.free(); // get resources dict->lookup("Resources", &resObj); resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; // check for a transparency group transpGroup = isolated = knockout = gFalse; blendingColorSpace = NULL; if (dict->lookup("Group", &obj1)->isDict()) { if (obj1.dictLookup("S", &obj2)->isName("Transparency")) { transpGroup = gTrue; if (!obj1.dictLookup("CS", &obj3)->isNull()) { blendingColorSpace = GfxColorSpace::parse(&obj3); } obj3.free(); if (obj1.dictLookup("I", &obj3)->isBool()) { isolated = obj3.getBool(); } obj3.free(); if (obj1.dictLookup("K", &obj3)->isBool()) { knockout = obj3.getBool(); } obj3.free(); } obj2.free(); } obj1.free(); // draw it ++formDepth; drawForm(str, resDict, m, bbox, transpGroup, gFalse, blendingColorSpace, isolated, knockout); --formDepth; if (blendingColorSpace) { delete blendingColorSpace; } resObj.free(); ocState = ocSaved; } void Gfx::drawForm(Object *str, Dict *resDict, double *matrix, double *bbox, GBool transpGroup, GBool softMask, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool alpha, Function *transferFunc, GfxColor *backdropColor) { Parser *oldParser; GfxState *savedState; double oldBaseMatrix[6]; int i; // push new resources on stack pushResources(resDict); // save current graphics state savedState = saveStateStack(); // kill any pre-existing path state->clearPath(); // save current parser oldParser = parser; // set form transformation matrix state->concatCTM(matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); out->updateCTM(state, matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5]); // set form bounding box state->moveTo(bbox[0], bbox[1]); state->lineTo(bbox[2], bbox[1]); state->lineTo(bbox[2], bbox[3]); state->lineTo(bbox[0], bbox[3]); state->closePath(); state->clip(); out->clip(state); state->clearPath(); if (softMask || transpGroup) { if (state->getBlendMode() != gfxBlendNormal) { state->setBlendMode(gfxBlendNormal); out->updateBlendMode(state); } if (state->getFillOpacity() != 1) { state->setFillOpacity(1); out->updateFillOpacity(state); } if (state->getStrokeOpacity() != 1) { state->setStrokeOpacity(1); out->updateStrokeOpacity(state); } out->clearSoftMask(state); out->beginTransparencyGroup(state, bbox, blendingColorSpace, isolated, knockout, softMask); } // set new base matrix for (i = 0; i < 6; ++i) { oldBaseMatrix[i] = baseMatrix[i]; baseMatrix[i] = state->getCTM()[i]; } // draw the form display(str, gFalse); if (softMask || transpGroup) { out->endTransparencyGroup(state); } // restore base matrix for (i = 0; i < 6; ++i) { baseMatrix[i] = oldBaseMatrix[i]; } // restore parser parser = oldParser; // restore graphics state restoreStateStack(savedState); // pop resource stack popResources(); if (softMask) { out->setSoftMask(state, bbox, alpha, transferFunc, backdropColor); } else if (transpGroup) { out->paintTransparencyGroup(state, bbox); } return; } //------------------------------------------------------------------------ // in-line image operators //------------------------------------------------------------------------ void Gfx::opBeginImage(Object args[], int numArgs) { Stream *str; int c1, c2; // NB: this function is run even if ocState is false -- doImage() is // responsible for skipping over the inline image data // build dict/stream str = buildImageStream(); // display the image if (str) { doImage(NULL, str, gTrue); // skip 'EI' tag c1 = str->getUndecodedStream()->getChar(); c2 = str->getUndecodedStream()->getChar(); while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) { c1 = c2; c2 = str->getUndecodedStream()->getChar(); } delete str; } } Stream *Gfx::buildImageStream() { Object dict; Object obj; char *key; Stream *str; // build dictionary dict.initDict(xref); parser->getObj(&obj); while (!obj.isCmd("ID") && !obj.isEOF()) { if (!obj.isName()) { error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object"); obj.free(); } else { key = copyString(obj.getName()); obj.free(); parser->getObj(&obj); if (obj.isEOF() || obj.isError()) { gfree(key); break; } dict.dictAdd(key, &obj); } parser->getObj(&obj); } if (obj.isEOF()) { error(errSyntaxError, getPos(), "End of file in inline image"); obj.free(); dict.free(); return NULL; } obj.free(); // make stream if (!(str = parser->getStream())) { error(errSyntaxError, getPos(), "Invalid inline image data"); dict.free(); return NULL; } str = new EmbedStream(str, &dict, gFalse, 0); str = str->addFilters(&dict); return str; } void Gfx::opImageData(Object args[], int numArgs) { error(errInternal, getPos(), "Got 'ID' operator"); } void Gfx::opEndImage(Object args[], int numArgs) { error(errInternal, getPos(), "Got 'EI' operator"); } //------------------------------------------------------------------------ // type 3 font operators //------------------------------------------------------------------------ void Gfx::opSetCharWidth(Object args[], int numArgs) { out->type3D0(state, args[0].getNum(), args[1].getNum()); } void Gfx::opSetCacheDevice(Object args[], int numArgs) { out->type3D1(state, args[0].getNum(), args[1].getNum(), args[2].getNum(), args[3].getNum(), args[4].getNum(), args[5].getNum()); } //------------------------------------------------------------------------ // compatibility operators //------------------------------------------------------------------------ void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) { ++ignoreUndef; } void Gfx::opEndIgnoreUndef(Object args[], int numArgs) { if (ignoreUndef > 0) --ignoreUndef; } //------------------------------------------------------------------------ // marked content operators //------------------------------------------------------------------------ void Gfx::opBeginMarkedContent(Object args[], int numArgs) { GfxMarkedContent *mc; Object obj; GBool ocStateNew; GString *s; Unicode *u; int uLen, i; GfxMarkedContentKind mcKind; if (printCommands) { printf(" marked content: %s ", args[0].getName()); if (numArgs == 2) { args[1].print(stdout); } printf("\n"); fflush(stdout); } mcKind = gfxMCOther; if (args[0].isName("OC") && numArgs == 2 && args[1].isName() && res->lookupPropertiesNF(args[1].getName(), &obj)) { if (doc->getOptionalContent()->evalOCObject(&obj, &ocStateNew)) { ocState = ocStateNew; } obj.free(); mcKind = gfxMCOptionalContent; } else if (args[0].isName("Span") && numArgs == 2 && args[1].isDict()) { if (args[1].dictLookup("ActualText", &obj)->isString()) { s = obj.getString(); if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { uLen = (s->getLength() - 2) / 2; u = (Unicode *)gmallocn(uLen, sizeof(Unicode)); for (i = 0; i < uLen; ++i) { u[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { uLen = s->getLength(); u = (Unicode *)gmallocn(uLen, sizeof(Unicode)); for (i = 0; i < uLen; ++i) { u[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } } out->beginActualText(state, u, uLen); gfree(u); mcKind = gfxMCActualText; } obj.free(); } mc = new GfxMarkedContent(mcKind, ocState); markedContentStack->append(mc); } void Gfx::opEndMarkedContent(Object args[], int numArgs) { GfxMarkedContent *mc; GfxMarkedContentKind mcKind; if (markedContentStack->getLength() > 0) { mc = (GfxMarkedContent *) markedContentStack->del(markedContentStack->getLength() - 1); mcKind = mc->kind; delete mc; if (mcKind == gfxMCOptionalContent) { if (markedContentStack->getLength() > 0) { mc = (GfxMarkedContent *) markedContentStack->get(markedContentStack->getLength() - 1); ocState = mc->ocState; } else { ocState = gTrue; } } else if (mcKind == gfxMCActualText) { out->endActualText(state); } } else { error(errSyntaxWarning, getPos(), "Mismatched EMC operator"); } } void Gfx::opMarkPoint(Object args[], int numArgs) { if (printCommands) { printf(" mark point: %s ", args[0].getName()); if (numArgs == 2) args[1].print(stdout); printf("\n"); fflush(stdout); } } //------------------------------------------------------------------------ // misc //------------------------------------------------------------------------ void Gfx::drawAnnot(Object *str, AnnotBorderStyle *borderStyle, double xMin, double yMin, double xMax, double yMax) { Dict *dict, *resDict; Object matrixObj, bboxObj, resObj, obj1; double formXMin, formYMin, formXMax, formYMax; double x, y, sx, sy, tx, ty; double m[6], bbox[4]; double r, g, b; GfxColor color; double *dash, *dash2; int dashLength; int i; // this function assumes that we are in the default user space, // i.e., baseMatrix = ctm // if the bounding box has zero width or height, don't draw anything // at all if (xMin == xMax || yMin == yMax) { return; } // draw the appearance stream (if there is one) if (str->isStream()) { // get stream dict dict = str->streamGetDict(); // get the form bounding box dict->lookup("BBox", &bboxObj); if (!bboxObj.isArray()) { bboxObj.free(); error(errSyntaxError, getPos(), "Bad form bounding box"); return; } for (i = 0; i < 4; ++i) { bboxObj.arrayGet(i, &obj1); bbox[i] = obj1.getNum(); obj1.free(); } bboxObj.free(); // get the form matrix dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); m[i] = obj1.getNum(); obj1.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0; } matrixObj.free(); // transform the four corners of the form bbox to default user // space, and construct the transformed bbox x = bbox[0] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[1] * m[3] + m[5]; formXMin = formXMax = x; formYMin = formYMax = y; x = bbox[0] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[0] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) { formXMin = x; } else if (x > formXMax) { formXMax = x; } if (y < formYMin) { formYMin = y; } else if (y > formYMax) { formYMax = y; } x = bbox[2] * m[0] + bbox[1] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[1] * m[3] + m[5]; if (x < formXMin) { formXMin = x; } else if (x > formXMax) { formXMax = x; } if (y < formYMin) { formYMin = y; } else if (y > formYMax) { formYMax = y; } x = bbox[2] * m[0] + bbox[3] * m[2] + m[4]; y = bbox[2] * m[1] + bbox[3] * m[3] + m[5]; if (x < formXMin) { formXMin = x; } else if (x > formXMax) { formXMax = x; } if (y < formYMin) { formYMin = y; } else if (y > formYMax) { formYMax = y; } // construct a mapping matrix, [sx 0 0], which maps the transformed // [0 sy 0] // [tx ty 1] // bbox to the annotation rectangle if (formXMin == formXMax) { // this shouldn't happen sx = 1; } else { sx = (xMax - xMin) / (formXMax - formXMin); } if (formYMin == formYMax) { // this shouldn't happen sy = 1; } else { sy = (yMax - yMin) / (formYMax - formYMin); } tx = -formXMin * sx + xMin; ty = -formYMin * sy + yMin; // the final transform matrix is (form matrix) * (mapping matrix) m[0] *= sx; m[1] *= sy; m[2] *= sx; m[3] *= sy; m[4] = m[4] * sx + tx; m[5] = m[5] * sy + ty; // get the resources dict->lookup("Resources", &resObj); resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; // draw it drawForm(str, resDict, m, bbox); resObj.free(); } // draw the border if (borderStyle && borderStyle->getWidth() > 0) { if (state->getStrokeColorSpace()->getMode() != csDeviceRGB) { state->setStrokePattern(NULL); state->setStrokeColorSpace(new GfxDeviceRGBColorSpace()); out->updateStrokeColorSpace(state); } borderStyle->getColor(&r, &g, &b); color.c[0] = dblToCol(r); color.c[1] = dblToCol(g); color.c[2] = dblToCol(b); state->setStrokeColor(&color); out->updateStrokeColor(state); state->setLineWidth(borderStyle->getWidth()); out->updateLineWidth(state); borderStyle->getDash(&dash, &dashLength); if (borderStyle->getType() == annotBorderDashed && dashLength > 0) { dash2 = (double *)gmallocn(dashLength, sizeof(double)); memcpy(dash2, dash, dashLength * sizeof(double)); state->setLineDash(dash2, dashLength, 0); out->updateLineDash(state); } //~ this doesn't currently handle the beveled and engraved styles state->clearPath(); state->moveTo(xMin, yMin); state->lineTo(xMax, yMin); if (borderStyle->getType() != annotBorderUnderlined) { state->lineTo(xMax, yMax); state->lineTo(xMin, yMax); state->closePath(); } out->stroke(state); } } void Gfx::saveState() { out->saveState(state); state = state->save(); } void Gfx::restoreState() { state = state->restore(); out->restoreState(state); } // Create a new state stack, and initialize it with a copy of the // current state. GfxState *Gfx::saveStateStack() { GfxState *oldState; out->saveState(state); oldState = state; state = state->copy(gTrue); return oldState; } // Switch back to the previous state stack. void Gfx::restoreStateStack(GfxState *oldState) { while (state->hasSaves()) { restoreState(); } delete state; state = oldState; out->restoreState(state); } void Gfx::pushResources(Dict *resDict) { res = new GfxResources(xref, resDict, res); } void Gfx::popResources() { GfxResources *resPtr; resPtr = res->getNext(); delete res; res = resPtr; } xpdf-3.03/xpdf/forwardArrow.xbm0000644000076400007640000000045011622305345016042 0ustar dereknderekn#define forwardArrow_width 16 #define forwardArrow_height 15 static unsigned char forwardArrow_bits[] = { 0x00, 0x01, 0x00, 0x03, 0x00, 0x07, 0x00, 0x0f, 0x00, 0x1f, 0x33, 0x3f, 0x33, 0x7f, 0x33, 0xff, 0x33, 0x7f, 0x33, 0x3f, 0x00, 0x1f, 0x00, 0x0f, 0x00, 0x07, 0x00, 0x03, 0x00, 0x01}; xpdf-3.03/xpdf/XPDFApp.cc0000644000076400007640000003307611622305345014376 0ustar dereknderekn//======================================================================== // // XPDFApp.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "GString.h" #include "GList.h" #include "Error.h" #include "XPDFViewer.h" #include "XPDFApp.h" #include "config.h" // these macro defns conflict with xpdf's Object class #ifdef LESSTIF_VERSION #undef XtDisplay #undef XtScreen #undef XtWindow #undef XtParent #undef XtIsRealized #endif //------------------------------------------------------------------------ #define remoteCmdSize 512 //------------------------------------------------------------------------ static String fallbackResources[] = { "*.zoomComboBox*fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1", "*XmTextField.fontList: -*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1", "*.fontList: -*-helvetica-medium-r-normal--12-*-*-*-*-*-iso8859-1", "*XmTextField.translations: #override\\n" " Ctrla:beginning-of-line()\\n" " Ctrlb:backward-character()\\n" " Ctrld:delete-next-character()\\n" " Ctrle:end-of-line()\\n" " Ctrlf:forward-character()\\n" " Ctrlu:beginning-of-line()delete-to-end-of-line()\\n" " Ctrlk:delete-to-end-of-line()\\n", "*.toolTipEnable: True", "*.toolTipPostDelay: 1500", "*.toolTipPostDuration: 0", "*.TipLabel.foreground: black", "*.TipLabel.background: LightYellow", "*.TipShell.borderWidth: 1", "*.TipShell.borderColor: black", NULL }; static XrmOptionDescRec xOpts[] = { {"-display", ".display", XrmoptionSepArg, NULL}, {"-foreground", "*Foreground", XrmoptionSepArg, NULL}, {"-fg", "*Foreground", XrmoptionSepArg, NULL}, {"-background", "*Background", XrmoptionSepArg, NULL}, {"-bg", "*Background", XrmoptionSepArg, NULL}, {"-geometry", ".geometry", XrmoptionSepArg, NULL}, {"-g", ".geometry", XrmoptionSepArg, NULL}, {"-font", "*.fontList", XrmoptionSepArg, NULL}, {"-fn", "*.fontList", XrmoptionSepArg, NULL}, {"-title", ".title", XrmoptionSepArg, NULL}, {"-cmap", ".installCmap", XrmoptionNoArg, (XPointer)"on"}, {"-rgb", ".rgbCubeSize", XrmoptionSepArg, NULL}, {"-rv", ".reverseVideo", XrmoptionNoArg, (XPointer)"true"}, {"-papercolor", ".paperColor", XrmoptionSepArg, NULL}, {"-mattecolor", ".matteColor", XrmoptionSepArg, NULL}, {"-z", ".initialZoom", XrmoptionSepArg, NULL} }; #define nXOpts (sizeof(xOpts) / sizeof(XrmOptionDescRec)) struct XPDFAppResources { String geometry; String title; Bool installCmap; int rgbCubeSize; Bool reverseVideo; String paperColor; String matteColor; String fullScreenMatteColor; String initialZoom; }; static Bool defInstallCmap = False; static int defRGBCubeSize = defaultRGBCube; static Bool defReverseVideo = False; static XtResource xResources[] = { { "geometry", "Geometry", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, geometry), XtRString, (XtPointer)NULL }, { "title", "Title", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, title), XtRString, (XtPointer)NULL }, { "installCmap", "InstallCmap", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, installCmap), XtRBool, (XtPointer)&defInstallCmap }, { "rgbCubeSize", "RgbCubeSize", XtRInt, sizeof(int), XtOffsetOf(XPDFAppResources, rgbCubeSize), XtRInt, (XtPointer)&defRGBCubeSize }, { "reverseVideo", "ReverseVideo", XtRBool, sizeof(Bool), XtOffsetOf(XPDFAppResources, reverseVideo), XtRBool, (XtPointer)&defReverseVideo }, { "paperColor", "PaperColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, paperColor), XtRString, (XtPointer)NULL }, { "matteColor", "MatteColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, matteColor), XtRString, (XtPointer)"gray50" }, { "fullScreenMatteColor", "FullScreenMatteColor", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, fullScreenMatteColor), XtRString, (XtPointer)"black" }, { "initialZoom", "InitialZoom", XtRString, sizeof(String), XtOffsetOf(XPDFAppResources, initialZoom), XtRString, (XtPointer)NULL } }; #define nXResources (sizeof(xResources) / sizeof(XtResource)) //------------------------------------------------------------------------ // XPDFApp //------------------------------------------------------------------------ #if 0 //~ for debugging static int xErrorHandler(Display *display, XErrorEvent *ev) { printf("X error:\n"); printf(" resource ID = %08lx\n", ev->resourceid); printf(" serial = %lu\n", ev->serial); printf(" error_code = %d\n", ev->error_code); printf(" request_code = %d\n", ev->request_code); printf(" minor_code = %d\n", ev->minor_code); fflush(stdout); abort(); } #endif XPDFApp::XPDFApp(int *argc, char *argv[]) { appShell = XtAppInitialize(&appContext, xpdfAppName, xOpts, nXOpts, argc, argv, fallbackResources, NULL, 0); display = XtDisplay(appShell); screenNum = XScreenNumberOfScreen(XtScreen(appShell)); #if XmVERSION > 1 XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)), XmNenableButtonTab, True, NULL); #endif #if XmVERSION > 1 // Drag-and-drop appears to be buggy -- I'm seeing weird crashes // deep in the Motif code when I destroy widgets in the XpdfForms // code. Xpdf doesn't use it, so just turn it off. XtVaSetValues(XmGetXmDisplay(XtDisplay(appShell)), XmNdragInitiatorProtocolStyle, XmDRAG_NONE, XmNdragReceiverProtocolStyle, XmDRAG_NONE, NULL); #endif #if 0 //~ for debugging XSynchronize(display, True); XSetErrorHandler(&xErrorHandler); #endif fullScreen = gFalse; remoteAtom = None; remoteViewer = NULL; remoteWin = None; getResources(); viewers = new GList(); } void XPDFApp::getResources() { XPDFAppResources resources; XColor xcol, xcol2; Colormap colormap; XtGetApplicationResources(appShell, &resources, xResources, nXResources, NULL, 0); geometry = resources.geometry ? new GString(resources.geometry) : (GString *)NULL; title = resources.title ? new GString(resources.title) : (GString *)NULL; installCmap = (GBool)resources.installCmap; rgbCubeSize = resources.rgbCubeSize; reverseVideo = (GBool)resources.reverseVideo; if (reverseVideo) { paperRGB[0] = paperRGB[1] = paperRGB[2] = 0; paperPixel = BlackPixel(display, screenNum); } else { paperRGB[0] = paperRGB[1] = paperRGB[2] = 0xff; paperPixel = WhitePixel(display, screenNum); } XtVaGetValues(appShell, XmNcolormap, &colormap, NULL); if (resources.paperColor) { if (XAllocNamedColor(display, colormap, resources.paperColor, &xcol, &xcol2)) { paperRGB[0] = xcol.red >> 8; paperRGB[1] = xcol.green >> 8; paperRGB[2] = xcol.blue >> 8; paperPixel = xcol.pixel; } else { error(errIO, -1, "Couldn't allocate color '{0:s}'", resources.paperColor); } } if (XAllocNamedColor(display, colormap, resources.matteColor, &xcol, &xcol2)) { mattePixel = xcol.pixel; } else { mattePixel = paperPixel; } if (XAllocNamedColor(display, colormap, resources.fullScreenMatteColor, &xcol, &xcol2)) { fullScreenMattePixel = xcol.pixel; } else { fullScreenMattePixel = paperPixel; } initialZoom = resources.initialZoom ? new GString(resources.initialZoom) : (GString *)NULL; } XPDFApp::~XPDFApp() { deleteGList(viewers, XPDFViewer); if (geometry) { delete geometry; } if (title) { delete title; } if (initialZoom) { delete initialZoom; } } XPDFViewer *XPDFApp::open(GString *fileName, int page, GString *ownerPassword, GString *userPassword) { XPDFViewer *viewer; viewer = new XPDFViewer(this, fileName, page, NULL, fullScreen, ownerPassword, userPassword); if (!viewer->isOk()) { delete viewer; return NULL; } if (remoteAtom != None) { remoteViewer = viewer; remoteWin = viewer->getWindow(); XtAddEventHandler(remoteWin, PropertyChangeMask, False, &remoteMsgCbk, this); XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime); } viewers->append(viewer); return viewer; } XPDFViewer *XPDFApp::openAtDest(GString *fileName, GString *dest, GString *ownerPassword, GString *userPassword) { XPDFViewer *viewer; viewer = new XPDFViewer(this, fileName, 1, dest, fullScreen, ownerPassword, userPassword); if (!viewer->isOk()) { delete viewer; return NULL; } if (remoteAtom != None) { remoteViewer = viewer; remoteWin = viewer->getWindow(); XtAddEventHandler(remoteWin, PropertyChangeMask, False, &remoteMsgCbk, this); XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime); } viewers->append(viewer); return viewer; } XPDFViewer *XPDFApp::reopen(XPDFViewer *viewer, PDFDoc *doc, int page, GBool fullScreenA) { int i; for (i = 0; i < viewers->getLength(); ++i) { if (((XPDFViewer *)viewers->get(i)) == viewer) { viewers->del(i); delete viewer; } } viewer = new XPDFViewer(this, doc, page, NULL, fullScreenA); if (!viewer->isOk()) { delete viewer; return NULL; } if (remoteAtom != None) { remoteViewer = viewer; remoteWin = viewer->getWindow(); XtAddEventHandler(remoteWin, PropertyChangeMask, False, &remoteMsgCbk, this); XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime); } viewers->append(viewer); return viewer; } void XPDFApp::close(XPDFViewer *viewer, GBool closeLast) { int i; if (viewers->getLength() == 1) { if (viewer != (XPDFViewer *)viewers->get(0)) { return; } if (closeLast) { quit(); } else { viewer->clear(); } } else { for (i = 0; i < viewers->getLength(); ++i) { if (((XPDFViewer *)viewers->get(i)) == viewer) { viewers->del(i); if (remoteAtom != None && remoteViewer == viewer) { remoteViewer = (XPDFViewer *)viewers->get(viewers->getLength() - 1); remoteWin = remoteViewer->getWindow(); XSetSelectionOwner(display, remoteAtom, XtWindow(remoteWin), CurrentTime); } delete viewer; return; } } } } void XPDFApp::quit() { if (remoteAtom != None) { XSetSelectionOwner(display, remoteAtom, None, CurrentTime); } while (viewers->getLength() > 0) { delete (XPDFViewer *)viewers->del(0); } #if HAVE_XTAPPSETEXITFLAG XtAppSetExitFlag(appContext); #else exit(0); #endif } void XPDFApp::run() { XtAppMainLoop(appContext); } void XPDFApp::setRemoteName(char *remoteName) { remoteAtom = XInternAtom(display, remoteName, False); remoteXWin = XGetSelectionOwner(display, remoteAtom); } GBool XPDFApp::remoteServerRunning() { return remoteXWin != None; } void XPDFApp::remoteExec(char *cmd) { char cmd2[remoteCmdSize]; int n; n = strlen(cmd); if (n > remoteCmdSize - 2) { n = remoteCmdSize - 2; } memcpy(cmd2, cmd, n); cmd2[n] = '\n'; cmd2[n+1] = '\0'; XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)cmd2, n + 2); XFlush(display); } void XPDFApp::remoteOpen(GString *fileName, int page, GBool raise) { char cmd[remoteCmdSize]; sprintf(cmd, "openFileAtPage(%.200s,%d)\n", fileName->getCString(), page); if (raise) { strcat(cmd, "raise\n"); } XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1); XFlush(display); } void XPDFApp::remoteOpenAtDest(GString *fileName, GString *dest, GBool raise) { char cmd[remoteCmdSize]; sprintf(cmd, "openFileAtDest(%.200s,%.256s)\n", fileName->getCString(), dest->getCString()); if (raise) { strcat(cmd, "raise\n"); } XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1); XFlush(display); } void XPDFApp::remoteReload(GBool raise) { char cmd[remoteCmdSize]; strcpy(cmd, "reload\n"); if (raise) { strcat(cmd, "raise\n"); } XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)cmd, strlen(cmd) + 1); XFlush(display); } void XPDFApp::remoteRaise() { XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)"raise\n", 7); XFlush(display); } void XPDFApp::remoteQuit() { XChangeProperty(display, remoteXWin, remoteAtom, remoteAtom, 8, PropModeReplace, (Guchar *)"quit\n", 6); XFlush(display); } void XPDFApp::remoteMsgCbk(Widget widget, XtPointer ptr, XEvent *event, Boolean *cont) { XPDFApp *app = (XPDFApp *)ptr; char *cmd, *p0, *p1; Atom type; int format; Gulong size, remain; GString *cmdStr; if (event->xproperty.atom != app->remoteAtom) { *cont = True; return; } *cont = False; if (XGetWindowProperty(app->display, XtWindow(app->remoteWin), app->remoteAtom, 0, remoteCmdSize/4, True, app->remoteAtom, &type, &format, &size, &remain, (Guchar **)&cmd) != Success) { return; } if (!cmd) { return; } p0 = cmd; while (*p0 && (p1 = strchr(p0, '\n'))) { cmdStr = new GString(p0, p1 - p0); app->remoteViewer->execCmd(cmdStr, NULL); delete cmdStr; p0 = p1 + 1; } XFree((XPointer)cmd); } xpdf-3.03/xpdf/dblRightArrow.xbm0000644000076400007640000000045311622305345016140 0ustar dereknderekn#define dblRightArrow_width 16 #define dblRightArrow_height 15 static unsigned char dblRightArrow_bits[] = { 0x01, 0x01, 0x03, 0x03, 0x07, 0x07, 0x0f, 0x0f, 0x1f, 0x1f, 0x3f, 0x3f, 0x7f, 0x7f, 0xff, 0xff, 0x7f, 0x7f, 0x3f, 0x3f, 0x1f, 0x1f, 0x0f, 0x0f, 0x07, 0x07, 0x03, 0x03, 0x01, 0x01}; xpdf-3.03/xpdf/PDFDocEncoding.cc0000644000076400007640000000467311622305345015703 0ustar dereknderekn//======================================================================== // // PDFDocEncoding.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include "PDFDocEncoding.h" Unicode pdfDocEncoding[256] = { 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, // 00 0x0008, 0x0009, 0x000a, 0x000b, 0x000c, 0x000d, 0x000e, 0x000f, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017, // 10 0x02d8, 0x02c7, 0x02c6, 0x02d9, 0x02dd, 0x02db, 0x02da, 0x02dc, 0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027, // 20 0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037, // 30 0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047, // 40 0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f, 0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057, // 50 0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f, 0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067, // 60 0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f, 0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077, // 70 0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x0000, 0x2022, 0x2020, 0x2021, 0x2026, 0x2014, 0x2013, 0x0192, 0x2044, // 80 0x2039, 0x203a, 0x2212, 0x2030, 0x201e, 0x201c, 0x201d, 0x2018, 0x2019, 0x201a, 0x2122, 0xfb01, 0xfb02, 0x0141, 0x0152, 0x0160, // 90 0x0178, 0x017d, 0x0131, 0x0142, 0x0153, 0x0161, 0x017e, 0x0000, 0x20ac, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6, 0x00a7, // a0 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x0000, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3, 0x00b4, 0x00b5, 0x00b6, 0x00b7, // b0 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0, 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, // c0 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd, 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, // d0 0x00d8, 0x00d9, 0x00da, 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7, // e0 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4, 0x00f5, 0x00f6, 0x00f7, // f0 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff }; xpdf-3.03/xpdf/JPXStream.cc0000644000076400007640000030264611622305345015013 0ustar dereknderekn//======================================================================== // // JPXStream.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "Error.h" #include "JArithmeticDecoder.h" #include "JPXStream.h" //~ to do: // - precincts // - ROI // - progression order changes // - packed packet headers // - support for palettes, channel maps, etc. // - make sure all needed JP2/JPX subboxes are parsed (readBoxes) // - can we assume that QCC segments must come after the QCD segment? // - handle tilePartToEOC in readTilePartData // - progression orders 2, 3, and 4 // - in coefficient decoding (readCodeBlockData): // - selective arithmetic coding bypass // (this also affects reading the cb->dataLen array) // - coeffs longer than 31 bits (should just ignore the extra bits?) // - handle boxes larger than 2^32 bytes // - the fixed-point arithmetic won't handle 16-bit pixels //------------------------------------------------------------------------ // number of contexts for the arithmetic decoder #define jpxNContexts 19 #define jpxContextSigProp 0 // 0 - 8: significance prop and cleanup #define jpxContextSign 9 // 9 - 13: sign #define jpxContextMagRef 14 // 14 -16: magnitude refinement #define jpxContextRunLength 17 // cleanup: run length #define jpxContextUniform 18 // cleanup: first signif coeff //------------------------------------------------------------------------ #define jpxPassSigProp 0 #define jpxPassMagRef 1 #define jpxPassCleanup 2 //------------------------------------------------------------------------ // arithmetic decoder context for the significance propagation and // cleanup passes: // [horiz][vert][diag][subband] // where subband = 0 for HL // = 1 for LH and LL // = 2 for HH static Guint sigPropContext[3][3][5][3] = { {{{ 0, 0, 0 }, // horiz=0, vert=0, diag=0 { 1, 1, 3 }, // horiz=0, vert=0, diag=1 { 2, 2, 6 }, // horiz=0, vert=0, diag=2 { 2, 2, 8 }, // horiz=0, vert=0, diag=3 { 2, 2, 8 }}, // horiz=0, vert=0, diag=4 {{ 5, 3, 1 }, // horiz=0, vert=1, diag=0 { 6, 3, 4 }, // horiz=0, vert=1, diag=1 { 6, 3, 7 }, // horiz=0, vert=1, diag=2 { 6, 3, 8 }, // horiz=0, vert=1, diag=3 { 6, 3, 8 }}, // horiz=0, vert=1, diag=4 {{ 8, 4, 2 }, // horiz=0, vert=2, diag=0 { 8, 4, 5 }, // horiz=0, vert=2, diag=1 { 8, 4, 7 }, // horiz=0, vert=2, diag=2 { 8, 4, 8 }, // horiz=0, vert=2, diag=3 { 8, 4, 8 }}}, // horiz=0, vert=2, diag=4 {{{ 3, 5, 1 }, // horiz=1, vert=0, diag=0 { 3, 6, 4 }, // horiz=1, vert=0, diag=1 { 3, 6, 7 }, // horiz=1, vert=0, diag=2 { 3, 6, 8 }, // horiz=1, vert=0, diag=3 { 3, 6, 8 }}, // horiz=1, vert=0, diag=4 {{ 7, 7, 2 }, // horiz=1, vert=1, diag=0 { 7, 7, 5 }, // horiz=1, vert=1, diag=1 { 7, 7, 7 }, // horiz=1, vert=1, diag=2 { 7, 7, 8 }, // horiz=1, vert=1, diag=3 { 7, 7, 8 }}, // horiz=1, vert=1, diag=4 {{ 8, 7, 2 }, // horiz=1, vert=2, diag=0 { 8, 7, 5 }, // horiz=1, vert=2, diag=1 { 8, 7, 7 }, // horiz=1, vert=2, diag=2 { 8, 7, 8 }, // horiz=1, vert=2, diag=3 { 8, 7, 8 }}}, // horiz=1, vert=2, diag=4 {{{ 4, 8, 2 }, // horiz=2, vert=0, diag=0 { 4, 8, 5 }, // horiz=2, vert=0, diag=1 { 4, 8, 7 }, // horiz=2, vert=0, diag=2 { 4, 8, 8 }, // horiz=2, vert=0, diag=3 { 4, 8, 8 }}, // horiz=2, vert=0, diag=4 {{ 7, 8, 2 }, // horiz=2, vert=1, diag=0 { 7, 8, 5 }, // horiz=2, vert=1, diag=1 { 7, 8, 7 }, // horiz=2, vert=1, diag=2 { 7, 8, 8 }, // horiz=2, vert=1, diag=3 { 7, 8, 8 }}, // horiz=2, vert=1, diag=4 {{ 8, 8, 2 }, // horiz=2, vert=2, diag=0 { 8, 8, 5 }, // horiz=2, vert=2, diag=1 { 8, 8, 7 }, // horiz=2, vert=2, diag=2 { 8, 8, 8 }, // horiz=2, vert=2, diag=3 { 8, 8, 8 }}} // horiz=2, vert=2, diag=4 }; // arithmetic decoder context and xor bit for the sign bit in the // significance propagation pass: // [horiz][vert][k] // where horiz/vert are offset by 2 (i.e., range is -2 .. 2) // and k = 0 for the context // = 1 for the xor bit static Guint signContext[5][5][2] = { {{ 13, 1 }, // horiz=-2, vert=-2 { 13, 1 }, // horiz=-2, vert=-1 { 12, 1 }, // horiz=-2, vert= 0 { 11, 1 }, // horiz=-2, vert=+1 { 11, 1 }}, // horiz=-2, vert=+2 {{ 13, 1 }, // horiz=-1, vert=-2 { 13, 1 }, // horiz=-1, vert=-1 { 12, 1 }, // horiz=-1, vert= 0 { 11, 1 }, // horiz=-1, vert=+1 { 11, 1 }}, // horiz=-1, vert=+2 {{ 10, 1 }, // horiz= 0, vert=-2 { 10, 1 }, // horiz= 0, vert=-1 { 9, 0 }, // horiz= 0, vert= 0 { 10, 0 }, // horiz= 0, vert=+1 { 10, 0 }}, // horiz= 0, vert=+2 {{ 11, 0 }, // horiz=+1, vert=-2 { 11, 0 }, // horiz=+1, vert=-1 { 12, 0 }, // horiz=+1, vert= 0 { 13, 0 }, // horiz=+1, vert=+1 { 13, 0 }}, // horiz=+1, vert=+2 {{ 11, 0 }, // horiz=+2, vert=-2 { 11, 0 }, // horiz=+2, vert=-1 { 12, 0 }, // horiz=+2, vert= 0 { 13, 0 }, // horiz=+2, vert=+1 { 13, 0 }}, // horiz=+2, vert=+2 }; //------------------------------------------------------------------------ // constants used in the IDWT #define idwtAlpha -1.586134342059924 #define idwtBeta -0.052980118572961 #define idwtGamma 0.882911075530934 #define idwtDelta 0.443506852043971 #define idwtKappa 1.230174104914001 #define idwtIKappa (1.0 / idwtKappa) // number of bits to the right of the decimal point for the fixed // point arithmetic used in the IDWT #define fracBits 16 //------------------------------------------------------------------------ // floor(x / y) #define jpxFloorDiv(x, y) ((x) / (y)) // floor(x / 2^y) #define jpxFloorDivPow2(x, y) ((x) >> (y)) // ceil(x / y) #define jpxCeilDiv(x, y) (((x) + (y) - 1) / (y)) // ceil(x / 2^y) #define jpxCeilDivPow2(x, y) (((x) + (1 << (y)) - 1) >> (y)) //------------------------------------------------------------------------ #if 1 //----- disable coverage tracking #define cover(idx) #else //----- enable coverage tracking class JPXCover { public: JPXCover(int sizeA); ~JPXCover(); void incr(int idx); private: int size, used; int *data; }; JPXCover::JPXCover(int sizeA) { size = sizeA; used = -1; data = (int *)gmallocn(size, sizeof(int)); memset(data, 0, size * sizeof(int)); } JPXCover::~JPXCover() { int i; printf("JPX coverage:\n"); for (i = 0; i <= used; ++i) { printf(" %4d: %8d\n", i, data[i]); } gfree(data); } void JPXCover::incr(int idx) { if (idx < size) { ++data[idx]; if (idx > used) { used = idx; } } } JPXCover jpxCover(150); #define cover(idx) jpxCover.incr(idx) #endif //----- coverage tracking //------------------------------------------------------------------------ JPXStream::JPXStream(Stream *strA): FilterStream(strA) { bufStr = new BufStream(str, 2); nComps = 0; bpc = NULL; width = height = 0; haveCS = gFalse; havePalette = gFalse; haveCompMap = gFalse; haveChannelDefn = gFalse; img.tiles = NULL; bitBuf = 0; bitBufLen = 0; bitBufSkip = gFalse; byteCount = 0; } JPXStream::~JPXStream() { close(); delete bufStr; } void JPXStream::reset() { bufStr->reset(); if (readBoxes()) { curY = img.yOffset; } else { // readBoxes reported an error, so we go immediately to EOF curY = img.ySize; } curX = img.xOffset; curComp = 0; readBufLen = 0; } void JPXStream::close() { JPXTile *tile; JPXTileComp *tileComp; JPXResLevel *resLevel; JPXPrecinct *precinct; JPXSubband *subband; JPXCodeBlock *cb; Guint comp, i, k, r, pre, sb; gfree(bpc); bpc = NULL; if (havePalette) { gfree(palette.bpc); gfree(palette.c); havePalette = gFalse; } if (haveCompMap) { gfree(compMap.comp); gfree(compMap.type); gfree(compMap.pComp); haveCompMap = gFalse; } if (haveChannelDefn) { gfree(channelDefn.idx); gfree(channelDefn.type); gfree(channelDefn.assoc); haveChannelDefn = gFalse; } if (img.tiles) { for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { tile = &img.tiles[i]; if (tile->tileComps) { for (comp = 0; comp < img.nComps; ++comp) { tileComp = &tile->tileComps[comp]; gfree(tileComp->quantSteps); gfree(tileComp->data); gfree(tileComp->buf); if (tileComp->resLevels) { for (r = 0; r <= tileComp->nDecompLevels; ++r) { resLevel = &tileComp->resLevels[r]; if (resLevel->precincts) { for (pre = 0; pre < 1; ++pre) { precinct = &resLevel->precincts[pre]; if (precinct->subbands) { for (sb = 0; sb < (Guint)(r == 0 ? 1 : 3); ++sb) { subband = &precinct->subbands[sb]; gfree(subband->inclusion); gfree(subband->zeroBitPlane); if (subband->cbs) { for (k = 0; k < subband->nXCBs * subband->nYCBs; ++k) { cb = &subband->cbs[k]; gfree(cb->dataLen); gfree(cb->touched); if (cb->arithDecoder) { delete cb->arithDecoder; } if (cb->stats) { delete cb->stats; } } gfree(subband->cbs); } } gfree(precinct->subbands); } } gfree(img.tiles[i].tileComps[comp].resLevels[r].precincts); } } gfree(img.tiles[i].tileComps[comp].resLevels); } } gfree(img.tiles[i].tileComps); } } gfree(img.tiles); img.tiles = NULL; } bufStr->close(); } int JPXStream::getChar() { int c; if (readBufLen < 8) { fillReadBuf(); } if (readBufLen == 8) { c = readBuf & 0xff; readBufLen = 0; } else if (readBufLen > 8) { c = (readBuf >> (readBufLen - 8)) & 0xff; readBufLen -= 8; } else if (readBufLen == 0) { c = EOF; } else { c = (readBuf << (8 - readBufLen)) & 0xff; readBufLen = 0; } return c; } int JPXStream::lookChar() { int c; if (readBufLen < 8) { fillReadBuf(); } if (readBufLen == 8) { c = readBuf & 0xff; } else if (readBufLen > 8) { c = (readBuf >> (readBufLen - 8)) & 0xff; } else if (readBufLen == 0) { c = EOF; } else { c = (readBuf << (8 - readBufLen)) & 0xff; } return c; } void JPXStream::fillReadBuf() { JPXTileComp *tileComp; Guint tileIdx, tx, ty; int pix, pixBits; do { if (curY >= img.ySize) { return; } tileIdx = ((curY - img.yTileOffset) / img.yTileSize) * img.nXTiles + (curX - img.xTileOffset) / img.xTileSize; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid tileComp = &img.tiles[tileIdx].tileComps[curComp]; #else tileComp = &img.tiles[tileIdx].tileComps[havePalette ? 0 : curComp]; #endif tx = jpxCeilDiv((curX - img.xTileOffset) % img.xTileSize, tileComp->hSep); ty = jpxCeilDiv((curY - img.yTileOffset) % img.yTileSize, tileComp->vSep); pix = (int)tileComp->data[ty * (tileComp->x1 - tileComp->x0) + tx]; pixBits = tileComp->prec; #if 1 //~ ignore the palette, assume the PDF ColorSpace object is valid if (++curComp == img.nComps) { #else if (havePalette) { if (pix >= 0 && pix < palette.nEntries) { pix = palette.c[pix * palette.nComps + curComp]; } else { pix = 0; } pixBits = palette.bpc[curComp]; } if (++curComp == (Guint)(havePalette ? palette.nComps : img.nComps)) { #endif curComp = 0; if (++curX == img.xSize) { curX = img.xOffset; ++curY; if (pixBits < 8) { pix <<= 8 - pixBits; pixBits = 8; } } } if (pixBits == 8) { readBuf = (readBuf << 8) | (pix & 0xff); } else { readBuf = (readBuf << pixBits) | (pix & ((1 << pixBits) - 1)); } readBufLen += pixBits; } while (readBufLen < 8); } GString *JPXStream::getPSFilter(int psLevel, const char *indent) { return NULL; } GBool JPXStream::isBinary(GBool last) { return str->isBinary(gTrue); } void JPXStream::getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) { Guint boxType, boxLen, dataLen, csEnum; Guint bpc1, dummy, i; int csMeth, csPrec, csPrec1, dummy2; StreamColorSpaceMode csMode1; GBool haveBPC, haveCSMode; csPrec = 0; // make gcc happy haveBPC = haveCSMode = gFalse; bufStr->reset(); if (bufStr->lookChar() == 0xff) { getImageParams2(bitsPerComponent, csMode); } else { while (readBoxHdr(&boxType, &boxLen, &dataLen)) { if (boxType == 0x6a703268) { // JP2 header cover(0); // skip the superbox } else if (boxType == 0x69686472) { // image header cover(1); if (readULong(&dummy) && readULong(&dummy) && readUWord(&dummy) && readUByte(&bpc1) && readUByte(&dummy) && readUByte(&dummy) && readUByte(&dummy)) { *bitsPerComponent = bpc1 + 1; haveBPC = gTrue; } } else if (boxType == 0x636F6C72) { // color specification cover(2); if (readByte(&csMeth) && readByte(&csPrec1) && readByte(&dummy2)) { if (csMeth == 1) { if (readULong(&csEnum)) { csMode1 = streamCSNone; if (csEnum == jpxCSBiLevel || csEnum == jpxCSGrayscale) { csMode1 = streamCSDeviceGray; } else if (csEnum == jpxCSCMYK) { csMode1 = streamCSDeviceCMYK; } else if (csEnum == jpxCSsRGB || csEnum == jpxCSCISesRGB || csEnum == jpxCSROMMRGB) { csMode1 = streamCSDeviceRGB; } if (csMode1 != streamCSNone && (!haveCSMode || csPrec1 > csPrec)) { *csMode = csMode1; csPrec = csPrec1; haveCSMode = gTrue; } for (i = 0; i < dataLen - 7; ++i) { bufStr->getChar(); } } } else { for (i = 0; i < dataLen - 3; ++i) { bufStr->getChar(); } } } } else if (boxType == 0x6A703263) { // codestream cover(3); if (!(haveBPC && haveCSMode)) { getImageParams2(bitsPerComponent, csMode); } break; } else { cover(4); for (i = 0; i < dataLen; ++i) { bufStr->getChar(); } } } } bufStr->close(); } // Get image parameters from the codestream. void JPXStream::getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode) { int segType; Guint segLen, nComps1, bpc1, dummy, i; while (readMarkerHdr(&segType, &segLen)) { if (segType == 0x51) { // SIZ - image and tile size cover(5); if (readUWord(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readULong(&dummy) && readUWord(&nComps1) && readUByte(&bpc1)) { *bitsPerComponent = (bpc1 & 0x7f) + 1; // if there's no color space info, take a guess if (nComps1 == 1) { *csMode = streamCSDeviceGray; } else if (nComps1 == 3) { *csMode = streamCSDeviceRGB; } else if (nComps1 == 4) { *csMode = streamCSDeviceCMYK; } } break; } else { cover(6); if (segLen > 2) { for (i = 0; i < segLen - 2; ++i) { bufStr->getChar(); } } } } } GBool JPXStream::readBoxes() { Guint boxType, boxLen, dataLen; Guint bpc1, compression, unknownColorspace, ipr; Guint i, j; haveImgHdr = gFalse; // check for a naked JPEG 2000 codestream (without the JP2/JPX // wrapper) -- this appears to be a violation of the PDF spec, but // Acrobat allows it if (bufStr->lookChar() == 0xff) { cover(7); error(errSyntaxWarning, getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); if (!readCodestream(0)) { return gFalse; } nComps = img.nComps; bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = img.tiles[0].tileComps[i].prec; } width = img.xSize - img.xOffset; height = img.ySize - img.yOffset; return gTrue; } while (readBoxHdr(&boxType, &boxLen, &dataLen)) { switch (boxType) { case 0x6a703268: // JP2 header // this is a grouping box ('superbox') which has no real // contents and doesn't appear to be used consistently, i.e., // some things which should be subboxes of the JP2 header box // show up outside of it - so we simply ignore the JP2 header // box cover(8); break; case 0x69686472: // image header cover(9); if (!readULong(&height) || !readULong(&width) || !readUWord(&nComps) || !readUByte(&bpc1) || !readUByte(&compression) || !readUByte(&unknownColorspace) || !readUByte(&ipr)) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } if (compression != 7) { error(errSyntaxError, getPos(), "Unknown compression type in JPX stream"); return gFalse; } bpc = (Guint *)gmallocn(nComps, sizeof(Guint)); for (i = 0; i < nComps; ++i) { bpc[i] = bpc1; } haveImgHdr = gTrue; break; case 0x62706363: // bits per component cover(10); if (!haveImgHdr) { error(errSyntaxError, getPos(), "Found bits per component box before image header box in JPX stream"); return gFalse; } if (dataLen != nComps) { error(errSyntaxError, getPos(), "Invalid bits per component box in JPX stream"); return gFalse; } for (i = 0; i < nComps; ++i) { if (!readUByte(&bpc[i])) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } } break; case 0x636F6C72: // color specification cover(11); if (!readColorSpecBox(dataLen)) { return gFalse; } break; case 0x70636c72: // palette cover(12); if (!readUWord(&palette.nEntries) || !readUByte(&palette.nComps)) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } palette.bpc = (Guint *)gmallocn(palette.nComps, sizeof(Guint)); palette.c = (int *)gmallocn(palette.nEntries * palette.nComps, sizeof(int)); for (i = 0; i < palette.nComps; ++i) { if (!readUByte(&palette.bpc[i])) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } ++palette.bpc[i]; } for (i = 0; i < palette.nEntries; ++i) { for (j = 0; j < palette.nComps; ++j) { if (!readNBytes(((palette.bpc[j] & 0x7f) + 7) >> 3, (palette.bpc[j] & 0x80) ? gTrue : gFalse, &palette.c[i * palette.nComps + j])) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } } } havePalette = gTrue; break; case 0x636d6170: // component mapping cover(13); compMap.nChannels = dataLen / 4; compMap.comp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); compMap.type = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); compMap.pComp = (Guint *)gmallocn(compMap.nChannels, sizeof(Guint)); for (i = 0; i < compMap.nChannels; ++i) { if (!readUWord(&compMap.comp[i]) || !readUByte(&compMap.type[i]) || !readUByte(&compMap.pComp[i])) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } } haveCompMap = gTrue; break; case 0x63646566: // channel definition cover(14); if (!readUWord(&channelDefn.nChannels)) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } channelDefn.idx = (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.type = (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); channelDefn.assoc = (Guint *)gmallocn(channelDefn.nChannels, sizeof(Guint)); for (i = 0; i < channelDefn.nChannels; ++i) { if (!readUWord(&channelDefn.idx[i]) || !readUWord(&channelDefn.type[i]) || !readUWord(&channelDefn.assoc[i])) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } } haveChannelDefn = gTrue; break; case 0x6A703263: // contiguous codestream cover(15); if (!bpc) { error(errSyntaxError, getPos(), "JPX stream is missing the image header box"); } if (!haveCS) { error(errSyntaxError, getPos(), "JPX stream has no supported color spec"); } if (!readCodestream(dataLen)) { return gFalse; } break; default: cover(16); for (i = 0; i < dataLen; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Unexpected EOF in JPX stream"); return gFalse; } } break; } } return gTrue; } GBool JPXStream::readColorSpecBox(Guint dataLen) { JPXColorSpec newCS; Guint csApprox, csEnum; Guint i; GBool ok; ok = gFalse; if (!readUByte(&newCS.meth) || !readByte(&newCS.prec) || !readUByte(&csApprox)) { goto err; } switch (newCS.meth) { case 1: // enumerated colorspace cover(17); if (!readULong(&csEnum)) { goto err; } newCS.enumerated.type = (JPXColorSpaceType)csEnum; switch (newCS.enumerated.type) { case jpxCSBiLevel: ok = gTrue; break; case jpxCSYCbCr1: ok = gTrue; break; case jpxCSYCbCr2: ok = gTrue; break; case jpxCSYCBCr3: ok = gTrue; break; case jpxCSPhotoYCC: ok = gTrue; break; case jpxCSCMY: ok = gTrue; break; case jpxCSCMYK: ok = gTrue; break; case jpxCSYCCK: ok = gTrue; break; case jpxCSCIELab: if (dataLen == 7 + 7*4) { if (!readULong(&newCS.enumerated.cieLab.rl) || !readULong(&newCS.enumerated.cieLab.ol) || !readULong(&newCS.enumerated.cieLab.ra) || !readULong(&newCS.enumerated.cieLab.oa) || !readULong(&newCS.enumerated.cieLab.rb) || !readULong(&newCS.enumerated.cieLab.ob) || !readULong(&newCS.enumerated.cieLab.il)) { goto err; } } else if (dataLen == 7) { //~ this assumes the 8-bit case cover(92); newCS.enumerated.cieLab.rl = 100; newCS.enumerated.cieLab.ol = 0; newCS.enumerated.cieLab.ra = 255; newCS.enumerated.cieLab.oa = 128; newCS.enumerated.cieLab.rb = 255; newCS.enumerated.cieLab.ob = 96; newCS.enumerated.cieLab.il = 0x00443530; } else { goto err; } ok = gTrue; break; case jpxCSsRGB: ok = gTrue; break; case jpxCSGrayscale: ok = gTrue; break; case jpxCSBiLevel2: ok = gTrue; break; case jpxCSCIEJab: // not allowed in PDF goto err; case jpxCSCISesRGB: ok = gTrue; break; case jpxCSROMMRGB: ok = gTrue; break; case jpxCSsRGBYCbCr: ok = gTrue; break; case jpxCSYPbPr1125: ok = gTrue; break; case jpxCSYPbPr1250: ok = gTrue; break; default: goto err; } break; case 2: // restricted ICC profile case 3: // any ICC profile (JPX) case 4: // vendor color (JPX) cover(18); for (i = 0; i < dataLen - 3; ++i) { if (bufStr->getChar() == EOF) { goto err; } } break; } if (ok && (!haveCS || newCS.prec > cs.prec)) { cs = newCS; haveCS = gTrue; } return gTrue; err: error(errSyntaxError, getPos(), "Error in JPX color spec"); return gFalse; } GBool JPXStream::readCodestream(Guint len) { JPXTile *tile; JPXTileComp *tileComp; int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; Guint precinctSize, style; Guint segLen, capabilities, comp, i, j, r; //----- main header haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; do { if (!readMarkerHdr(&segType, &segLen)) { error(errSyntaxError, getPos(), "Error in JPX codestream"); return gFalse; } switch (segType) { case 0x4f: // SOC - start of codestream // marker only cover(19); break; case 0x51: // SIZ - image and tile size cover(20); if (haveSIZ) { error(errSyntaxError, getPos(), "Duplicate SIZ marker segment in JPX stream"); return gFalse; } if (!readUWord(&capabilities) || !readULong(&img.xSize) || !readULong(&img.ySize) || !readULong(&img.xOffset) || !readULong(&img.yOffset) || !readULong(&img.xTileSize) || !readULong(&img.yTileSize) || !readULong(&img.xTileOffset) || !readULong(&img.yTileOffset) || !readUWord(&img.nComps)) { error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment"); return gFalse; } if (haveImgHdr && img.nComps != nComps) { error(errSyntaxError, getPos(), "Different number of components in JPX SIZ marker segment"); return gFalse; } if (img.xSize == 0 || img.ySize == 0 || img.xOffset >= img.xSize || img.yOffset >= img.ySize || img.xTileSize == 0 || img.yTileSize == 0 || img.xTileOffset > img.xOffset || img.yTileOffset > img.yOffset || img.xTileSize + img.xTileOffset <= img.xOffset || img.yTileSize + img.yTileOffset <= img.yOffset) { error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment"); return gFalse; } img.nXTiles = (img.xSize - img.xTileOffset + img.xTileSize - 1) / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) / img.yTileSize; // check for overflow before allocating memory if (img.nXTiles <= 0 || img.nYTiles <= 0 || img.nXTiles >= INT_MAX / img.nYTiles) { error(errSyntaxError, getPos(), "Bad tile count in JPX SIZ marker segment"); return gFalse; } img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { img.tiles[i].init = gFalse; img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, sizeof(JPXTileComp)); for (comp = 0; comp < img.nComps; ++comp) { img.tiles[i].tileComps[comp].quantSteps = NULL; img.tiles[i].tileComps[comp].data = NULL; img.tiles[i].tileComps[comp].buf = NULL; img.tiles[i].tileComps[comp].resLevels = NULL; } } for (comp = 0; comp < img.nComps; ++comp) { if (!readUByte(&img.tiles[0].tileComps[comp].prec) || !readUByte(&img.tiles[0].tileComps[comp].hSep) || !readUByte(&img.tiles[0].tileComps[comp].vSep)) { error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment"); return gFalse; } if (img.tiles[0].tileComps[comp].hSep == 0 || img.tiles[0].tileComps[comp].vSep == 0) { error(errSyntaxError, getPos(), "Error in JPX SIZ marker segment"); return gFalse; } img.tiles[0].tileComps[comp].sgned = (img.tiles[0].tileComps[comp].prec & 0x80) ? gTrue : gFalse; img.tiles[0].tileComps[comp].prec = (img.tiles[0].tileComps[comp].prec & 0x7f) + 1; for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { img.tiles[i].tileComps[comp] = img.tiles[0].tileComps[comp]; } } haveSIZ = gTrue; break; case 0x52: // COD - coding style default cover(21); if (!haveSIZ) { error(errSyntaxError, getPos(), "JPX COD marker segment before SIZ segment"); return gFalse; } if (!readUByte(&img.tiles[0].tileComps[0].style) || !readUByte(&img.tiles[0].progOrder) || !readUWord(&img.tiles[0].nLayers) || !readUByte(&img.tiles[0].multiComp) || !readUByte(&img.tiles[0].tileComps[0].nDecompLevels) || !readUByte(&img.tiles[0].tileComps[0].codeBlockW) || !readUByte(&img.tiles[0].tileComps[0].codeBlockH) || !readUByte(&img.tiles[0].tileComps[0].codeBlockStyle) || !readUByte(&img.tiles[0].tileComps[0].transform)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } if (img.tiles[0].tileComps[0].nDecompLevels > 32 || img.tiles[0].tileComps[0].codeBlockW > 8 || img.tiles[0].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[0].tileComps[0].codeBlockW += 2; img.tiles[0].tileComps[0].codeBlockH += 2; for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { if (i != 0) { img.tiles[i].progOrder = img.tiles[0].progOrder; img.tiles[i].nLayers = img.tiles[0].nLayers; img.tiles[i].multiComp = img.tiles[0].multiComp; } for (comp = 0; comp < img.nComps; ++comp) { if (!(i == 0 && comp == 0)) { img.tiles[i].tileComps[comp].style = img.tiles[0].tileComps[0].style; img.tiles[i].tileComps[comp].nDecompLevels = img.tiles[0].tileComps[0].nDecompLevels; img.tiles[i].tileComps[comp].codeBlockW = img.tiles[0].tileComps[0].codeBlockW; img.tiles[i].tileComps[comp].codeBlockH = img.tiles[0].tileComps[0].codeBlockH; img.tiles[i].tileComps[comp].codeBlockStyle = img.tiles[0].tileComps[0].codeBlockStyle; img.tiles[i].tileComps[comp].transform = img.tiles[0].tileComps[0].transform; } img.tiles[i].tileComps[comp].resLevels = (JPXResLevel *)gmallocn( (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; } } } for (r = 0; r <= img.tiles[0].tileComps[0].nDecompLevels; ++r) { if (img.tiles[0].tileComps[0].style & 0x01) { cover(91); if (!readUByte(&precinctSize)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[0].tileComps[0].resLevels[r].precinctWidth = precinctSize & 0x0f; img.tiles[0].tileComps[0].resLevels[r].precinctHeight = (precinctSize >> 4) & 0x0f; } else { img.tiles[0].tileComps[0].resLevels[r].precinctWidth = 15; img.tiles[0].tileComps[0].resLevels[r].precinctHeight = 15; } } for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { for (comp = 0; comp < img.nComps; ++comp) { if (!(i == 0 && comp == 0)) { for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = img.tiles[0].tileComps[0].resLevels[r].precinctWidth; img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = img.tiles[0].tileComps[0].resLevels[r].precinctHeight; } } } } haveCOD = gTrue; break; case 0x53: // COC - coding style component cover(22); if (!haveCOD) { error(errSyntaxError, getPos(), "JPX COC marker segment before COD segment"); return gFalse; } if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || !readUByte(&img.tiles[0].tileComps[comp].nDecompLevels) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[0].tileComps[comp].codeBlockStyle) || !readUByte(&img.tiles[0].tileComps[comp].transform)) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } if (img.tiles[0].tileComps[comp].nDecompLevels > 32 || img.tiles[0].tileComps[comp].codeBlockW > 8 || img.tiles[0].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } img.tiles[0].tileComps[comp].style = (img.tiles[0].tileComps[comp].style & ~1) | (style & 1); img.tiles[0].tileComps[comp].codeBlockW += 2; img.tiles[0].tileComps[comp].codeBlockH += 2; for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { if (i != 0) { img.tiles[i].tileComps[comp].style = img.tiles[0].tileComps[comp].style; img.tiles[i].tileComps[comp].nDecompLevels = img.tiles[0].tileComps[comp].nDecompLevels; img.tiles[i].tileComps[comp].codeBlockW = img.tiles[0].tileComps[comp].codeBlockW; img.tiles[i].tileComps[comp].codeBlockH = img.tiles[0].tileComps[comp].codeBlockH; img.tiles[i].tileComps[comp].codeBlockStyle = img.tiles[0].tileComps[comp].codeBlockStyle; img.tiles[i].tileComps[comp].transform = img.tiles[0].tileComps[comp].transform; } img.tiles[i].tileComps[comp].resLevels = (JPXResLevel *)greallocn( img.tiles[i].tileComps[comp].resLevels, (img.tiles[i].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precincts = NULL; } } for (r = 0; r <= img.tiles[0].tileComps[comp].nDecompLevels; ++r) { if (img.tiles[0].tileComps[comp].style & 0x01) { if (!readUByte(&precinctSize)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = precinctSize & 0x0f; img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = (precinctSize >> 4) & 0x0f; } else { img.tiles[0].tileComps[comp].resLevels[r].precinctWidth = 15; img.tiles[0].tileComps[comp].resLevels[r].precinctHeight = 15; } } for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { for (r = 0; r <= img.tiles[i].tileComps[comp].nDecompLevels; ++r) { img.tiles[i].tileComps[comp].resLevels[r].precinctWidth = img.tiles[0].tileComps[comp].resLevels[r].precinctWidth; img.tiles[i].tileComps[comp].resLevels[r].precinctHeight = img.tiles[0].tileComps[comp].resLevels[r].precinctHeight; } } break; case 0x5c: // QCD - quantization default cover(23); if (!haveSIZ) { error(errSyntaxError, getPos(), "JPX QCD marker segment before SIZ segment"); return gFalse; } if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x00) { if (segLen <= 3) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } img.tiles[0].tileComps[0].nQuantSteps = segLen - 3; img.tiles[0].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[0].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x01) { img.tiles[0].tileComps[0].nQuantSteps = 1; img.tiles[0].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[0])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } else if ((img.tiles[0].tileComps[0].quantStyle & 0x1f) == 0x02) { if (segLen < 5) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } img.tiles[0].tileComps[0].nQuantSteps = (segLen - 3) / 2; img.tiles[0].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[0].quantSteps, img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[0].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { for (comp = 0; comp < img.nComps; ++comp) { if (!(i == 0 && comp == 0)) { img.tiles[i].tileComps[comp].quantStyle = img.tiles[0].tileComps[0].quantStyle; img.tiles[i].tileComps[comp].nQuantSteps = img.tiles[0].tileComps[0].nQuantSteps; img.tiles[i].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, img.tiles[0].tileComps[0].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[0].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = img.tiles[0].tileComps[0].quantSteps[j]; } } } } haveQCD = gTrue; break; case 0x5d: // QCC - quantization component cover(24); if (!haveQCD) { error(errSyntaxError, getPos(), "JPX QCC marker segment before QCD segment"); return gFalse; } if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&img.tiles[0].tileComps[comp].quantStyle)) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x00) { if (segLen <= (img.nComps > 256 ? 5U : 4U)) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } img.tiles[0].tileComps[comp].nQuantSteps = segLen - (img.nComps > 256 ? 5 : 4); img.tiles[0].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[0].tileComps[comp].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } } } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x01) { img.tiles[0].tileComps[comp].nQuantSteps = 1; img.tiles[0].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[0])) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } } else if ((img.tiles[0].tileComps[comp].quantStyle & 0x1f) == 0x02) { if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } img.tiles[0].tileComps[comp].nQuantSteps = (segLen - (img.nComps > 256 ? 5 : 4)) / 2; img.tiles[0].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[0].tileComps[comp].quantSteps, img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[0].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[0].tileComps[comp].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } for (i = 1; i < img.nXTiles * img.nYTiles; ++i) { img.tiles[i].tileComps[comp].quantStyle = img.tiles[0].tileComps[comp].quantStyle; img.tiles[i].tileComps[comp].nQuantSteps = img.tiles[0].tileComps[comp].nQuantSteps; img.tiles[i].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[i].tileComps[comp].quantSteps, img.tiles[0].tileComps[comp].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[0].tileComps[comp].nQuantSteps; ++j) { img.tiles[i].tileComps[comp].quantSteps[j] = img.tiles[0].tileComps[comp].quantSteps[j]; } } break; case 0x5e: // RGN - region of interest cover(25); #if 1 //~ ROI is unimplemented error(errUnimplemented, -1, "got a JPX RGN segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX RGN marker segment"); return gFalse; } } #else if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&compInfo[comp].defROI.style) || !readUByte(&compInfo[comp].defROI.shift)) { error(errSyntaxError, getPos(), "Error in JPX RGN marker segment"); return gFalse; } #endif break; case 0x5f: // POC - progression order change cover(26); #if 1 //~ progression order changes are unimplemented error(errUnimplemented, -1, "got a JPX POC segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX POC marker segment"); return gFalse; } } #else nProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); progs = (JPXProgOrder *)gmallocn(nProgs, sizeof(JPXProgOrder)); for (i = 0; i < nProgs; ++i) { if (!readUByte(&progs[i].startRes) || !(img.nComps > 256 && readUWord(&progs[i].startComp)) || !(img.nComps <= 256 && readUByte(&progs[i].startComp)) || !readUWord(&progs[i].endLayer) || !readUByte(&progs[i].endRes) || !(img.nComps > 256 && readUWord(&progs[i].endComp)) || !(img.nComps <= 256 && readUByte(&progs[i].endComp)) || !readUByte(&progs[i].progOrder)) { error(errSyntaxError, getPos(), "Error in JPX POC marker segment"); return gFalse; } } #endif break; case 0x60: // PPM - packed packet headers, main header cover(27); #if 1 //~ packed packet headers are unimplemented error(errUnimplemented, -1, "Got a JPX PPM segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX PPM marker segment"); return gFalse; } } #endif break; case 0x55: // TLM - tile-part lengths // skipped cover(28); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX TLM marker segment"); return gFalse; } } break; case 0x57: // PLM - packet length, main header // skipped cover(29); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX PLM marker segment"); return gFalse; } } break; case 0x63: // CRG - component registration // skipped cover(30); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX CRG marker segment"); return gFalse; } } break; case 0x64: // COM - comment // skipped cover(31); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX COM marker segment"); return gFalse; } } break; case 0x90: // SOT - start of tile cover(32); haveSOT = gTrue; break; default: cover(33); error(errSyntaxError, getPos(), "Unknown marker segment {0:02x} in JPX stream", segType); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { break; } } break; } } while (!haveSOT); if (!haveSIZ) { error(errSyntaxError, getPos(), "Missing SIZ marker segment in JPX stream"); return gFalse; } if (!haveCOD) { error(errSyntaxError, getPos(), "Missing COD marker segment in JPX stream"); return gFalse; } if (!haveQCD) { error(errSyntaxError, getPos(), "Missing QCD marker segment in JPX stream"); return gFalse; } //----- read the tile-parts while (1) { if (!readTilePart()) { return gFalse; } if (!readMarkerHdr(&segType, &segLen)) { error(errSyntaxError, getPos(), "Error in JPX codestream"); return gFalse; } if (segType != 0x90) { // SOT - start of tile break; } } if (segType != 0xd9) { // EOC - end of codestream error(errSyntaxError, getPos(), "Missing EOC marker in JPX codestream"); return gFalse; } //----- finish decoding the image for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { tile = &img.tiles[i]; if (!tile->init) { error(errSyntaxError, getPos(), "Uninitialized tile in JPX codestream"); return gFalse; } for (comp = 0; comp < img.nComps; ++comp) { tileComp = &tile->tileComps[comp]; inverseTransform(tileComp); } if (!inverseMultiCompAndDC(tile)) { return gFalse; } } //~ can free memory below tileComps here, and also tileComp.buf return gTrue; } GBool JPXStream::readTilePart() { JPXTile *tile; JPXTileComp *tileComp; JPXResLevel *resLevel; JPXPrecinct *precinct; JPXSubband *subband; JPXCodeBlock *cb; int *sbCoeffs; GBool haveSOD; Guint tileIdx, tilePartLen, tilePartIdx, nTileParts; GBool tilePartToEOC; Guint precinctSize, style; Guint n, nSBs, nx, ny, sbx0, sby0, comp, segLen; Guint i, j, k, cbX, cbY, r, pre, sb, cbi, cbj; int segType, level; // process the SOT marker segment if (!readUWord(&tileIdx) || !readULong(&tilePartLen) || !readUByte(&tilePartIdx) || !readUByte(&nTileParts)) { error(errSyntaxError, getPos(), "Error in JPX SOT marker segment"); return gFalse; } if ((tilePartIdx > 0 && !img.tiles[tileIdx].init) || tileIdx >= img.nXTiles * img.nYTiles) { error(errSyntaxError, getPos(), "Weird tile index in JPX stream"); return gFalse; } tilePartToEOC = tilePartLen == 0; tilePartLen -= 12; // subtract size of SOT segment haveSOD = gFalse; do { if (!readMarkerHdr(&segType, &segLen)) { error(errSyntaxError, getPos(), "Error in JPX tile-part codestream"); return gFalse; } tilePartLen -= 2 + segLen; switch (segType) { case 0x52: // COD - coding style default cover(34); if (!readUByte(&img.tiles[tileIdx].tileComps[0].style) || !readUByte(&img.tiles[tileIdx].progOrder) || !readUWord(&img.tiles[tileIdx].nLayers) || !readUByte(&img.tiles[tileIdx].multiComp) || !readUByte(&img.tiles[tileIdx].tileComps[0].nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[0].codeBlockStyle) || !readUByte(&img.tiles[tileIdx].tileComps[0].transform)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } if (img.tiles[tileIdx].tileComps[0].nDecompLevels > 32 || img.tiles[tileIdx].tileComps[0].codeBlockW > 8 || img.tiles[tileIdx].tileComps[0].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[0].codeBlockW += 2; img.tiles[tileIdx].tileComps[0].codeBlockH += 2; for (comp = 0; comp < img.nComps; ++comp) { if (comp != 0) { img.tiles[tileIdx].tileComps[comp].style = img.tiles[tileIdx].tileComps[0].style; img.tiles[tileIdx].tileComps[comp].nDecompLevels = img.tiles[tileIdx].tileComps[0].nDecompLevels; img.tiles[tileIdx].tileComps[comp].codeBlockW = img.tiles[tileIdx].tileComps[0].codeBlockW; img.tiles[tileIdx].tileComps[comp].codeBlockH = img.tiles[tileIdx].tileComps[0].codeBlockH; img.tiles[tileIdx].tileComps[comp].codeBlockStyle = img.tiles[tileIdx].tileComps[0].codeBlockStyle; img.tiles[tileIdx].tileComps[comp].transform = img.tiles[tileIdx].tileComps[0].transform; } img.tiles[tileIdx].tileComps[comp].resLevels = (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; } } for (r = 0; r <= img.tiles[tileIdx].tileComps[0].nDecompLevels; ++r) { if (img.tiles[tileIdx].tileComps[0].style & 0x01) { if (!readUByte(&precinctSize)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = precinctSize & 0x0f; img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = (precinctSize >> 4) & 0x0f; } else { img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth = 15; img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight = 15; } } for (comp = 1; comp < img.nComps; ++comp) { for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = img.tiles[tileIdx].tileComps[0].resLevels[r].precinctWidth; img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = img.tiles[tileIdx].tileComps[0].resLevels[r].precinctHeight; } } break; case 0x53: // COC - coding style component cover(35); if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&style) || !readUByte(&img.tiles[tileIdx].tileComps[comp].nDecompLevels) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockW) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockH) || !readUByte(&img.tiles[tileIdx].tileComps[comp].codeBlockStyle) || !readUByte(&img.tiles[tileIdx].tileComps[comp].transform)) { error(errSyntaxError, getPos(), "Error in JPX COC marker segment"); return gFalse; } if (img.tiles[tileIdx].tileComps[comp].nDecompLevels > 32 || img.tiles[tileIdx].tileComps[comp].codeBlockW > 8 || img.tiles[tileIdx].tileComps[comp].codeBlockH > 8) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[comp].style = (img.tiles[tileIdx].tileComps[comp].style & ~1) | (style & 1); img.tiles[tileIdx].tileComps[comp].codeBlockW += 2; img.tiles[tileIdx].tileComps[comp].codeBlockH += 2; img.tiles[tileIdx].tileComps[comp].resLevels = (JPXResLevel *)greallocn( img.tiles[tileIdx].tileComps[comp].resLevels, (img.tiles[tileIdx].tileComps[comp].nDecompLevels + 1), sizeof(JPXResLevel)); for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { img.tiles[tileIdx].tileComps[comp].resLevels[r].precincts = NULL; } for (r = 0; r <= img.tiles[tileIdx].tileComps[comp].nDecompLevels; ++r) { if (img.tiles[tileIdx].tileComps[comp].style & 0x01) { if (!readUByte(&precinctSize)) { error(errSyntaxError, getPos(), "Error in JPX COD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = precinctSize & 0x0f; img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = (precinctSize >> 4) & 0x0f; } else { img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctWidth = 15; img.tiles[tileIdx].tileComps[comp].resLevels[r].precinctHeight = 15; } } break; case 0x5c: // QCD - quantization default cover(36); if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x00) { if (segLen <= 3) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[0].nQuantSteps = segLen - 3; img.tiles[tileIdx].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x01) { img.tiles[tileIdx].tileComps[0].nQuantSteps = 1; img.tiles[tileIdx].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[0])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } else if ((img.tiles[tileIdx].tileComps[0].quantStyle & 0x1f) == 0x02) { if (segLen < 5) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[0].nQuantSteps = (segLen - 3) / 2; img.tiles[tileIdx].tileComps[0].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[0].quantSteps, img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[0].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } for (comp = 1; comp < img.nComps; ++comp) { img.tiles[tileIdx].tileComps[comp].quantStyle = img.tiles[tileIdx].tileComps[0].quantStyle; img.tiles[tileIdx].tileComps[comp].nQuantSteps = img.tiles[tileIdx].tileComps[0].nQuantSteps; img.tiles[tileIdx].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, img.tiles[tileIdx].tileComps[0].nQuantSteps, sizeof(Guint)); for (j = 0; j < img.tiles[tileIdx].tileComps[0].nQuantSteps; ++j) { img.tiles[tileIdx].tileComps[comp].quantSteps[j] = img.tiles[tileIdx].tileComps[0].quantSteps[j]; } } break; case 0x5d: // QCC - quantization component cover(37); if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&img.tiles[tileIdx].tileComps[comp].quantStyle)) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x00) { if (segLen <= (img.nComps > 256 ? 5U : 4U)) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[comp].nQuantSteps = segLen - (img.nComps > 256 ? 5 : 4); img.tiles[tileIdx].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUByte(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } } } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x01) { img.tiles[tileIdx].tileComps[comp].nQuantSteps = 1; img.tiles[tileIdx].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[0])) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } } else if ((img.tiles[tileIdx].tileComps[comp].quantStyle & 0x1f) == 0x02) { if (segLen < (img.nComps > 256 ? 5U : 4U) + 2) { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } img.tiles[tileIdx].tileComps[comp].nQuantSteps = (segLen - (img.nComps > 256 ? 5 : 4)) / 2; img.tiles[tileIdx].tileComps[comp].quantSteps = (Guint *)greallocn(img.tiles[tileIdx].tileComps[comp].quantSteps, img.tiles[tileIdx].tileComps[comp].nQuantSteps, sizeof(Guint)); for (i = 0; i < img.tiles[tileIdx].tileComps[comp].nQuantSteps; ++i) { if (!readUWord(&img.tiles[tileIdx].tileComps[comp].quantSteps[i])) { error(errSyntaxError, getPos(), "Error in JPX QCD marker segment"); return gFalse; } } } else { error(errSyntaxError, getPos(), "Error in JPX QCC marker segment"); return gFalse; } break; case 0x5e: // RGN - region of interest cover(38); #if 1 //~ ROI is unimplemented error(errUnimplemented, -1, "Got a JPX RGN segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX RGN marker segment"); return gFalse; } } #else if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || !readUByte(&compInfo[comp].roi.style) || !readUByte(&compInfo[comp].roi.shift)) { error(errSyntaxError, getPos(), "Error in JPX RGN marker segment"); return gFalse; } #endif break; case 0x5f: // POC - progression order change cover(39); #if 1 //~ progression order changes are unimplemented error(errUnimplemented, -1, "Got a JPX POC segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX POC marker segment"); return gFalse; } } #else nTileProgs = (segLen - 2) / (img.nComps > 256 ? 9 : 7); tileProgs = (JPXProgOrder *)gmallocn(nTileProgs, sizeof(JPXProgOrder)); for (i = 0; i < nTileProgs; ++i) { if (!readUByte(&tileProgs[i].startRes) || !(img.nComps > 256 && readUWord(&tileProgs[i].startComp)) || !(img.nComps <= 256 && readUByte(&tileProgs[i].startComp)) || !readUWord(&tileProgs[i].endLayer) || !readUByte(&tileProgs[i].endRes) || !(img.nComps > 256 && readUWord(&tileProgs[i].endComp)) || !(img.nComps <= 256 && readUByte(&tileProgs[i].endComp)) || !readUByte(&tileProgs[i].progOrder)) { error(errSyntaxError, getPos(), "Error in JPX POC marker segment"); return gFalse; } } #endif break; case 0x61: // PPT - packed packet headers, tile-part hdr cover(40); #if 1 //~ packed packet headers are unimplemented error(errUnimplemented, -1, "Got a JPX PPT segment"); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX PPT marker segment"); return gFalse; } } #endif case 0x58: // PLT - packet length, tile-part header // skipped cover(41); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX PLT marker segment"); return gFalse; } } break; case 0x64: // COM - comment // skipped cover(42); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { error(errSyntaxError, getPos(), "Error in JPX COM marker segment"); return gFalse; } } break; case 0x93: // SOD - start of data cover(43); haveSOD = gTrue; break; default: cover(44); error(errSyntaxError, getPos(), "Unknown marker segment {0:02x} in JPX tile-part stream", segType); for (i = 0; i < segLen - 2; ++i) { if (bufStr->getChar() == EOF) { break; } } break; } } while (!haveSOD); //----- initialize the tile, precincts, and code-blocks if (tilePartIdx == 0) { tile = &img.tiles[tileIdx]; tile->init = gTrue; i = tileIdx / img.nXTiles; j = tileIdx % img.nXTiles; if ((tile->x0 = img.xTileOffset + j * img.xTileSize) < img.xOffset) { tile->x0 = img.xOffset; } if ((tile->y0 = img.yTileOffset + i * img.yTileSize) < img.yOffset) { tile->y0 = img.yOffset; } if ((tile->x1 = img.xTileOffset + (j + 1) * img.xTileSize) > img.xSize) { tile->x1 = img.xSize; } if ((tile->y1 = img.yTileOffset + (i + 1) * img.yTileSize) > img.ySize) { tile->y1 = img.ySize; } tile->comp = 0; tile->res = 0; tile->precinct = 0; tile->layer = 0; tile->maxNDecompLevels = 0; for (comp = 0; comp < img.nComps; ++comp) { tileComp = &tile->tileComps[comp]; if (tileComp->nDecompLevels > tile->maxNDecompLevels) { tile->maxNDecompLevels = tileComp->nDecompLevels; } tileComp->x0 = jpxCeilDiv(tile->x0, tileComp->hSep); tileComp->y0 = jpxCeilDiv(tile->y0, tileComp->vSep); tileComp->x1 = jpxCeilDiv(tile->x1, tileComp->hSep); tileComp->y1 = jpxCeilDiv(tile->y1, tileComp->vSep); tileComp->w = tileComp->x1 - tileComp->x0; tileComp->cbW = 1 << tileComp->codeBlockW; tileComp->cbH = 1 << tileComp->codeBlockH; tileComp->data = (int *)gmallocn((tileComp->x1 - tileComp->x0) * (tileComp->y1 - tileComp->y0), sizeof(int)); if (tileComp->x1 - tileComp->x0 > tileComp->y1 - tileComp->y0) { n = tileComp->x1 - tileComp->x0; } else { n = tileComp->y1 - tileComp->y0; } tileComp->buf = (int *)gmallocn(n + 8, sizeof(int)); for (r = 0; r <= tileComp->nDecompLevels; ++r) { resLevel = &tileComp->resLevels[r]; k = r == 0 ? tileComp->nDecompLevels : tileComp->nDecompLevels - r + 1; resLevel->x0 = jpxCeilDivPow2(tileComp->x0, k); resLevel->y0 = jpxCeilDivPow2(tileComp->y0, k); resLevel->x1 = jpxCeilDivPow2(tileComp->x1, k); resLevel->y1 = jpxCeilDivPow2(tileComp->y1, k); if (r == 0) { resLevel->bx0[0] = resLevel->x0; resLevel->by0[0] = resLevel->y0; resLevel->bx1[0] = resLevel->x1; resLevel->by1[0] = resLevel->y1; } else { resLevel->bx0[0] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); resLevel->by0[0] = resLevel->y0; resLevel->bx1[0] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); resLevel->by1[0] = resLevel->y1; resLevel->bx0[1] = resLevel->x0; resLevel->by0[1] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); resLevel->bx1[1] = resLevel->x1; resLevel->by1[1] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); resLevel->bx0[2] = jpxCeilDivPow2(tileComp->x0 - (1 << (k-1)), k); resLevel->by0[2] = jpxCeilDivPow2(tileComp->y0 - (1 << (k-1)), k); resLevel->bx1[2] = jpxCeilDivPow2(tileComp->x1 - (1 << (k-1)), k); resLevel->by1[2] = jpxCeilDivPow2(tileComp->y1 - (1 << (k-1)), k); } resLevel->precincts = (JPXPrecinct *)gmallocn(1, sizeof(JPXPrecinct)); for (pre = 0; pre < 1; ++pre) { precinct = &resLevel->precincts[pre]; precinct->x0 = resLevel->x0; precinct->y0 = resLevel->y0; precinct->x1 = resLevel->x1; precinct->y1 = resLevel->y1; nSBs = r == 0 ? 1 : 3; precinct->subbands = (JPXSubband *)gmallocn(nSBs, sizeof(JPXSubband)); for (sb = 0; sb < nSBs; ++sb) { subband = &precinct->subbands[sb]; subband->x0 = resLevel->bx0[sb]; subband->y0 = resLevel->by0[sb]; subband->x1 = resLevel->bx1[sb]; subband->y1 = resLevel->by1[sb]; subband->nXCBs = jpxCeilDivPow2(subband->x1, tileComp->codeBlockW) - jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); subband->nYCBs = jpxCeilDivPow2(subband->y1, tileComp->codeBlockH) - jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); n = subband->nXCBs > subband->nYCBs ? subband->nXCBs : subband->nYCBs; for (subband->maxTTLevel = 0, --n; n; ++subband->maxTTLevel, n >>= 1) ; n = 0; for (level = subband->maxTTLevel; level >= 0; --level) { nx = jpxCeilDivPow2(subband->nXCBs, level); ny = jpxCeilDivPow2(subband->nYCBs, level); n += nx * ny; } subband->inclusion = (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); subband->zeroBitPlane = (JPXTagTreeNode *)gmallocn(n, sizeof(JPXTagTreeNode)); for (k = 0; k < n; ++k) { subband->inclusion[k].finished = gFalse; subband->inclusion[k].val = 0; subband->zeroBitPlane[k].finished = gFalse; subband->zeroBitPlane[k].val = 0; } subband->cbs = (JPXCodeBlock *)gmallocn(subband->nXCBs * subband->nYCBs, sizeof(JPXCodeBlock)); sbx0 = jpxFloorDivPow2(subband->x0, tileComp->codeBlockW); sby0 = jpxFloorDivPow2(subband->y0, tileComp->codeBlockH); if (r == 0) { // (NL)LL sbCoeffs = tileComp->data; } else if (sb == 0) { // (NL-r+1)HL sbCoeffs = tileComp->data + resLevel->bx1[1] - resLevel->bx0[1]; } else if (sb == 1) { // (NL-r+1)LH sbCoeffs = tileComp->data + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w; } else { // (NL-r+1)HH sbCoeffs = tileComp->data + (resLevel->by1[0] - resLevel->by0[0]) * tileComp->w + resLevel->bx1[1] - resLevel->bx0[1]; } cb = subband->cbs; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { cb->x0 = (sbx0 + cbX) << tileComp->codeBlockW; cb->x1 = cb->x0 + tileComp->cbW; if (subband->x0 > cb->x0) { cb->x0 = subband->x0; } if (subband->x1 < cb->x1) { cb->x1 = subband->x1; } cb->y0 = (sby0 + cbY) << tileComp->codeBlockH; cb->y1 = cb->y0 + tileComp->cbH; if (subband->y0 > cb->y0) { cb->y0 = subband->y0; } if (subband->y1 < cb->y1) { cb->y1 = subband->y1; } cb->seen = gFalse; cb->lBlock = 3; cb->nextPass = jpxPassCleanup; cb->nZeroBitPlanes = 0; cb->dataLenSize = 1; cb->dataLen = (Guint *)gmalloc(sizeof(Guint)); cb->coeffs = sbCoeffs + (cb->y0 - subband->y0) * tileComp->w + (cb->x0 - subband->x0); cb->touched = (char *)gmalloc(1 << (tileComp->codeBlockW + tileComp->codeBlockH)); cb->len = 0; for (cbj = 0; cbj < cb->y1 - cb->y0; ++cbj) { for (cbi = 0; cbi < cb->x1 - cb->x0; ++cbi) { cb->coeffs[cbj * tileComp->w + cbi] = 0; } } memset(cb->touched, 0, (1 << (tileComp->codeBlockW + tileComp->codeBlockH))); cb->arithDecoder = NULL; cb->stats = NULL; ++cb; } } } } } } } return readTilePartData(tileIdx, tilePartLen, tilePartToEOC); } GBool JPXStream::readTilePartData(Guint tileIdx, Guint tilePartLen, GBool tilePartToEOC) { JPXTile *tile; JPXTileComp *tileComp; JPXResLevel *resLevel; JPXPrecinct *precinct; JPXSubband *subband; JPXCodeBlock *cb; Guint ttVal; Guint bits, cbX, cbY, nx, ny, i, j, n, sb; int level; tile = &img.tiles[tileIdx]; // read all packets from this tile-part while (1) { if (tilePartToEOC) { //~ peek for an EOC marker cover(93); } else if (tilePartLen == 0) { break; } tileComp = &tile->tileComps[tile->comp]; resLevel = &tileComp->resLevels[tile->res]; precinct = &resLevel->precincts[tile->precinct]; //----- packet header // setup startBitBuf(tilePartLen); if (tileComp->style & 0x02) { skipSOP(); } // zero-length flag if (!readBits(1, &bits)) { goto err; } if (!bits) { // packet is empty -- clear all code-block inclusion flags cover(45); for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { subband = &precinct->subbands[sb]; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { cb = &subband->cbs[cbY * subband->nXCBs + cbX]; cb->included = gFalse; } } } } else { for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { subband = &precinct->subbands[sb]; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { cb = &subband->cbs[cbY * subband->nXCBs + cbX]; // skip code-blocks with no coefficients if (cb->x0 >= cb->x1 || cb->y0 >= cb->y1) { cover(46); cb->included = gFalse; continue; } // code-block inclusion if (cb->seen) { cover(47); if (!readBits(1, &cb->included)) { goto err; } } else { cover(48); ttVal = 0; i = 0; for (level = subband->maxTTLevel; level >= 0; --level) { nx = jpxCeilDivPow2(subband->nXCBs, level); ny = jpxCeilDivPow2(subband->nYCBs, level); j = i + (cbY >> level) * nx + (cbX >> level); if (!subband->inclusion[j].finished && !subband->inclusion[j].val) { subband->inclusion[j].val = ttVal; } else { ttVal = subband->inclusion[j].val; } while (!subband->inclusion[j].finished && ttVal <= tile->layer) { if (!readBits(1, &bits)) { goto err; } if (bits == 1) { subband->inclusion[j].finished = gTrue; } else { ++ttVal; } } subband->inclusion[j].val = ttVal; if (ttVal > tile->layer) { break; } i += nx * ny; } cb->included = level < 0; } if (cb->included) { cover(49); // zero bit-plane count if (!cb->seen) { cover(50); ttVal = 0; i = 0; for (level = subband->maxTTLevel; level >= 0; --level) { nx = jpxCeilDivPow2(subband->nXCBs, level); ny = jpxCeilDivPow2(subband->nYCBs, level); j = i + (cbY >> level) * nx + (cbX >> level); if (!subband->zeroBitPlane[j].finished && !subband->zeroBitPlane[j].val) { subband->zeroBitPlane[j].val = ttVal; } else { ttVal = subband->zeroBitPlane[j].val; } while (!subband->zeroBitPlane[j].finished) { if (!readBits(1, &bits)) { goto err; } if (bits == 1) { subband->zeroBitPlane[j].finished = gTrue; } else { ++ttVal; } } subband->zeroBitPlane[j].val = ttVal; i += nx * ny; } cb->nZeroBitPlanes = ttVal; } // number of coding passes if (!readBits(1, &bits)) { goto err; } if (bits == 0) { cover(51); cb->nCodingPasses = 1; } else { if (!readBits(1, &bits)) { goto err; } if (bits == 0) { cover(52); cb->nCodingPasses = 2; } else { cover(53); if (!readBits(2, &bits)) { goto err; } if (bits < 3) { cover(54); cb->nCodingPasses = 3 + bits; } else { cover(55); if (!readBits(5, &bits)) { goto err; } if (bits < 31) { cover(56); cb->nCodingPasses = 6 + bits; } else { cover(57); if (!readBits(7, &bits)) { goto err; } cb->nCodingPasses = 37 + bits; } } } } // update Lblock while (1) { if (!readBits(1, &bits)) { goto err; } if (!bits) { break; } ++cb->lBlock; } // one codeword segment for each of the coding passes if (tileComp->codeBlockStyle & 0x04) { if (cb->nCodingPasses > cb->dataLenSize) { cb->dataLenSize = cb->nCodingPasses; cb->dataLen = (Guint *)greallocn(cb->dataLen, cb->dataLenSize, sizeof(Guint)); } // read the lengths for (i = 0; i < cb->nCodingPasses; ++i) { if (!readBits(cb->lBlock, &cb->dataLen[i])) { goto err; } } // one codeword segment for all of the coding passes } else { // read the length for (n = cb->lBlock, i = cb->nCodingPasses >> 1; i; ++n, i >>= 1) ; if (!readBits(n, &cb->dataLen[0])) { goto err; } } } } } } } if (tileComp->style & 0x04) { skipEPH(); } tilePartLen = finishBitBuf(); //----- packet data for (sb = 0; sb < (Guint)(tile->res == 0 ? 1 : 3); ++sb) { subband = &precinct->subbands[sb]; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { cb = &subband->cbs[cbY * subband->nXCBs + cbX]; if (cb->included) { if (!readCodeBlockData(tileComp, resLevel, precinct, subband, tile->res, sb, cb)) { return gFalse; } if (tileComp->codeBlockStyle & 0x04) { for (i = 0; i < cb->nCodingPasses; ++i) { tilePartLen -= cb->dataLen[i]; } } else { tilePartLen -= cb->dataLen[0]; } cb->seen = gTrue; } } } } //----- next packet switch (tile->progOrder) { case 0: // layer, resolution level, component, precinct cover(58); if (++tile->comp == img.nComps) { tile->comp = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; if (++tile->layer == tile->nLayers) { tile->layer = 0; } } } break; case 1: // resolution level, layer, component, precinct cover(59); if (++tile->comp == img.nComps) { tile->comp = 0; if (++tile->layer == tile->nLayers) { tile->layer = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; } } } break; case 2: // resolution level, precinct, component, layer //~ this isn't correct -- see B.12.1.3 cover(60); if (++tile->layer == tile->nLayers) { tile->layer = 0; if (++tile->comp == img.nComps) { tile->comp = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; } } } break; case 3: // precinct, component, resolution level, layer //~ this isn't correct -- see B.12.1.4 cover(61); if (++tile->layer == tile->nLayers) { tile->layer = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; if (++tile->comp == img.nComps) { tile->comp = 0; } } } break; case 4: // component, precinct, resolution level, layer //~ this isn't correct -- see B.12.1.5 cover(62); if (++tile->layer == tile->nLayers) { tile->layer = 0; if (++tile->res == tile->maxNDecompLevels + 1) { tile->res = 0; if (++tile->comp == img.nComps) { tile->comp = 0; } } } break; } } return gTrue; err: error(errSyntaxError, getPos(), "Error in JPX stream"); return gFalse; } GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, JPXResLevel *resLevel, JPXPrecinct *precinct, JPXSubband *subband, Guint res, Guint sb, JPXCodeBlock *cb) { int *coeff0, *coeff1, *coeff; char *touched0, *touched1, *touched; Guint horiz, vert, diag, all, cx, xorBit; int horizSign, vertSign, bit; int segSym; Guint i, x, y0, y1; if (cb->arithDecoder) { cover(63); cb->arithDecoder->restart(cb->dataLen[0]); } else { cover(64); cb->arithDecoder = new JArithmeticDecoder(); cb->arithDecoder->setStream(bufStr, cb->dataLen[0]); cb->arithDecoder->start(); cb->stats = new JArithmeticDecoderStats(jpxNContexts); cb->stats->setEntry(jpxContextSigProp, 4, 0); cb->stats->setEntry(jpxContextRunLength, 3, 0); cb->stats->setEntry(jpxContextUniform, 46, 0); } for (i = 0; i < cb->nCodingPasses; ++i) { if ((tileComp->codeBlockStyle & 0x04) && i > 0) { cb->arithDecoder->setStream(bufStr, cb->dataLen[i]); cb->arithDecoder->start(); } switch (cb->nextPass) { //----- significance propagation pass case jpxPassSigProp: cover(65); for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched; y0 < cb->y1; y0 += 4, coeff0 += 4 * tileComp->w, touched0 += 4 << tileComp->codeBlockW) { for (x = cb->x0, coeff1 = coeff0, touched1 = touched0; x < cb->x1; ++x, ++coeff1, ++touched1) { for (y1 = 0, coeff = coeff1, touched = touched1; y1 < 4 && y0+y1 < cb->y1; ++y1, coeff += tileComp->w, touched += tileComp->cbW) { if (!*coeff) { horiz = vert = diag = 0; horizSign = vertSign = 2; if (x > cb->x0) { if (coeff[-1]) { ++horiz; horizSign += coeff[-1] < 0 ? -1 : 1; } if (y0+y1 > cb->y0) { diag += coeff[-(int)tileComp->w - 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { diag += coeff[tileComp->w - 1] ? 1 : 0; } } if (x < cb->x1 - 1) { if (coeff[1]) { ++horiz; horizSign += coeff[1] < 0 ? -1 : 1; } if (y0+y1 > cb->y0) { diag += coeff[-(int)tileComp->w + 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { diag += coeff[tileComp->w + 1] ? 1 : 0; } } if (y0+y1 > cb->y0) { if (coeff[-(int)tileComp->w]) { ++vert; vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1; } } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { if (coeff[tileComp->w]) { ++vert; vertSign += coeff[tileComp->w] < 0 ? -1 : 1; } } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; if (cx != 0) { if (cb->arithDecoder->decodeBit(cx, cb->stats)) { cx = signContext[horizSign][vertSign][0]; xorBit = signContext[horizSign][vertSign][1]; if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { *coeff = -1; } else { *coeff = 1; } } *touched = 1; } } } } } ++cb->nextPass; break; //----- magnitude refinement pass case jpxPassMagRef: cover(66); for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched; y0 < cb->y1; y0 += 4, coeff0 += 4 * tileComp->w, touched0 += 4 << tileComp->codeBlockW) { for (x = cb->x0, coeff1 = coeff0, touched1 = touched0; x < cb->x1; ++x, ++coeff1, ++touched1) { for (y1 = 0, coeff = coeff1, touched = touched1; y1 < 4 && y0+y1 < cb->y1; ++y1, coeff += tileComp->w, touched += tileComp->cbW) { if (*coeff && !*touched) { if (*coeff == 1 || *coeff == -1) { all = 0; if (x > cb->x0) { all += coeff[-1] ? 1 : 0; if (y0+y1 > cb->y0) { all += coeff[-(int)tileComp->w - 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { all += coeff[tileComp->w - 1] ? 1 : 0; } } if (x < cb->x1 - 1) { all += coeff[1] ? 1 : 0; if (y0+y1 > cb->y0) { all += coeff[-(int)tileComp->w + 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { all += coeff[tileComp->w + 1] ? 1 : 0; } } if (y0+y1 > cb->y0) { all += coeff[-(int)tileComp->w] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { all += coeff[tileComp->w] ? 1 : 0; } cx = all ? 15 : 14; } else { cx = 16; } bit = cb->arithDecoder->decodeBit(cx, cb->stats); if (*coeff < 0) { *coeff = (*coeff << 1) - bit; } else { *coeff = (*coeff << 1) + bit; } *touched = 1; } } } } ++cb->nextPass; break; //----- cleanup pass case jpxPassCleanup: cover(67); for (y0 = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched; y0 < cb->y1; y0 += 4, coeff0 += 4 * tileComp->w, touched0 += 4 << tileComp->codeBlockW) { for (x = cb->x0, coeff1 = coeff0, touched1 = touched0; x < cb->x1; ++x, ++coeff1, ++touched1) { y1 = 0; if (y0 + 3 < cb->y1 && !(*touched1) && !(touched1[tileComp->cbW]) && !(touched1[2 * tileComp->cbW]) && !(touched1[3 * tileComp->cbW]) && (x == cb->x0 || y0 == cb->y0 || !coeff1[-(int)tileComp->w - 1]) && (y0 == cb->y0 || !coeff1[-(int)tileComp->w]) && (x == cb->x1 - 1 || y0 == cb->y0 || !coeff1[-(int)tileComp->w + 1]) && (x == cb->x0 || (!coeff1[-1] && !coeff1[tileComp->w - 1] && !coeff1[2 * tileComp->w - 1] && !coeff1[3 * tileComp->w - 1])) && (x == cb->x1 - 1 || (!coeff1[1] && !coeff1[tileComp->w + 1] && !coeff1[2 * tileComp->w + 1] && !coeff1[3 * tileComp->w + 1])) && ((tileComp->codeBlockStyle & 0x08) || ((x == cb->x0 || y0+4 == cb->y1 || !coeff1[4 * tileComp->w - 1]) && (y0+4 == cb->y1 || !coeff1[4 * tileComp->w]) && (x == cb->x1 - 1 || y0+4 == cb->y1 || !coeff1[4 * tileComp->w + 1])))) { if (cb->arithDecoder->decodeBit(jpxContextRunLength, cb->stats)) { y1 = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); y1 = (y1 << 1) | cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); coeff = &coeff1[y1 * tileComp->w]; cx = signContext[2][2][0]; xorBit = signContext[2][2][1]; if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { *coeff = -1; } else { *coeff = 1; } ++y1; } else { y1 = 4; } } for (coeff = &coeff1[y1 * tileComp->w], touched = &touched1[y1 << tileComp->codeBlockW]; y1 < 4 && y0 + y1 < cb->y1; ++y1, coeff += tileComp->w, touched += tileComp->cbW) { if (!*touched) { horiz = vert = diag = 0; horizSign = vertSign = 2; if (x > cb->x0) { if (coeff[-1]) { ++horiz; horizSign += coeff[-1] < 0 ? -1 : 1; } if (y0+y1 > cb->y0) { diag += coeff[-(int)tileComp->w - 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { diag += coeff[tileComp->w - 1] ? 1 : 0; } } if (x < cb->x1 - 1) { if (coeff[1]) { ++horiz; horizSign += coeff[1] < 0 ? -1 : 1; } if (y0+y1 > cb->y0) { diag += coeff[-(int)tileComp->w + 1] ? 1 : 0; } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { diag += coeff[tileComp->w + 1] ? 1 : 0; } } if (y0+y1 > cb->y0) { if (coeff[-(int)tileComp->w]) { ++vert; vertSign += coeff[-(int)tileComp->w] < 0 ? -1 : 1; } } if (y0+y1 < cb->y1 - 1 && (!(tileComp->codeBlockStyle & 0x08) || y1 < 3)) { if (coeff[tileComp->w]) { ++vert; vertSign += coeff[tileComp->w] < 0 ? -1 : 1; } } cx = sigPropContext[horiz][vert][diag][res == 0 ? 1 : sb]; if (cb->arithDecoder->decodeBit(cx, cb->stats)) { cx = signContext[horizSign][vertSign][0]; xorBit = signContext[horizSign][vertSign][1]; if (cb->arithDecoder->decodeBit(cx, cb->stats) ^ xorBit) { *coeff = -1; } else { *coeff = 1; } } } else { *touched = 0; } } } } ++cb->len; // look for a segmentation symbol if (tileComp->codeBlockStyle & 0x20) { segSym = cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats) << 3; segSym |= cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats) << 2; segSym |= cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats) << 1; segSym |= cb->arithDecoder->decodeBit(jpxContextUniform, cb->stats); if (segSym != 0x0a) { // in theory this should be a fatal error, but it seems to // be problematic error(errSyntaxWarning, getPos(), "Missing or invalid segmentation symbol in JPX stream"); } } cb->nextPass = jpxPassSigProp; break; } if (tileComp->codeBlockStyle & 0x02) { cb->stats->reset(); cb->stats->setEntry(jpxContextSigProp, 4, 0); cb->stats->setEntry(jpxContextRunLength, 3, 0); cb->stats->setEntry(jpxContextUniform, 46, 0); } if (tileComp->codeBlockStyle & 0x04) { cb->arithDecoder->cleanup(); } } cb->arithDecoder->cleanup(); return gTrue; } // Inverse quantization, and wavelet transform (IDWT). This also does // the initial shift to convert to fixed point format. void JPXStream::inverseTransform(JPXTileComp *tileComp) { JPXResLevel *resLevel; JPXPrecinct *precinct; JPXSubband *subband; JPXCodeBlock *cb; int *coeff0, *coeff; char *touched0, *touched; Guint qStyle, guard, eps, shift; int shift2; double mu; int val; Guint r, cbX, cbY, x, y; cover(68); //----- (NL)LL subband (resolution level 0) resLevel = &tileComp->resLevels[0]; precinct = &resLevel->precincts[0]; subband = &precinct->subbands[0]; // i-quant parameters qStyle = tileComp->quantStyle & 0x1f; guard = (tileComp->quantStyle >> 5) & 7; if (qStyle == 0) { cover(69); eps = (tileComp->quantSteps[0] >> 3) & 0x1f; shift = guard + eps - 1; mu = 0; // make gcc happy } else { cover(70); shift = guard - 1 + tileComp->prec; mu = (double)(0x800 + (tileComp->quantSteps[0] & 0x7ff)) / 2048.0; } if (tileComp->transform == 0) { cover(71); shift += fracBits; } // do fixed point adjustment and dequantization on (NL)LL cb = subband->cbs; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched; y < cb->y1; ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) { for (x = cb->x0, coeff = coeff0, touched = touched0; x < cb->x1; ++x, ++coeff, ++touched) { val = *coeff; if (val != 0) { shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched); if (shift2 > 0) { cover(94); if (val < 0) { val = (val << shift2) - (1 << (shift2 - 1)); } else { val = (val << shift2) + (1 << (shift2 - 1)); } } else { cover(95); val >>= -shift2; } if (qStyle == 0) { cover(96); if (tileComp->transform == 0) { cover(97); val &= -1 << fracBits; } } else { cover(98); val = (int)((double)val * mu); } } *coeff = val; } } ++cb; } } //----- IDWT for each level for (r = 1; r <= tileComp->nDecompLevels; ++r) { resLevel = &tileComp->resLevels[r]; // (n)LL is already in the upper-left corner of the // tile-component data array -- interleave with (n)HL/LH/HH // and inverse transform to get (n-1)LL, which will be stored // in the upper-left corner of the tile-component data array inverseTransformLevel(tileComp, r, resLevel); } } // Do one level of the inverse transform: // - take (n)LL, (n)HL, (n)LH, and (n)HH from the upper-left corner // of the tile-component data array // - leave the resulting (n-1)LL in the same place void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, Guint r, JPXResLevel *resLevel) { JPXPrecinct *precinct; JPXSubband *subband; JPXCodeBlock *cb; int *coeff0, *coeff; char *touched0, *touched; Guint qStyle, guard, eps, shift, t; int shift2; double mu; int val; int *dataPtr, *bufPtr; Guint nx1, nx2, ny1, ny2, offset; Guint x, y, sb, cbX, cbY; //----- fixed-point adjustment and dequantization qStyle = tileComp->quantStyle & 0x1f; guard = (tileComp->quantStyle >> 5) & 7; precinct = &resLevel->precincts[0]; for (sb = 0; sb < 3; ++sb) { // i-quant parameters if (qStyle == 0) { cover(100); eps = (tileComp->quantSteps[3*r - 2 + sb] >> 3) & 0x1f; shift = guard + eps - 1; mu = 0; // make gcc happy } else { cover(101); shift = guard + tileComp->prec; if (sb == 2) { cover(102); ++shift; } t = tileComp->quantSteps[qStyle == 1 ? 0 : (3*r - 2 + sb)]; mu = (double)(0x800 + (t & 0x7ff)) / 2048.0; } if (tileComp->transform == 0) { cover(103); shift += fracBits; } // fixed point adjustment and dequantization subband = &precinct->subbands[sb]; cb = subband->cbs; for (cbY = 0; cbY < subband->nYCBs; ++cbY) { for (cbX = 0; cbX < subband->nXCBs; ++cbX) { for (y = cb->y0, coeff0 = cb->coeffs, touched0 = cb->touched; y < cb->y1; ++y, coeff0 += tileComp->w, touched0 += tileComp->cbW) { for (x = cb->x0, coeff = coeff0, touched = touched0; x < cb->x1; ++x, ++coeff, ++touched) { val = *coeff; if (val != 0) { shift2 = shift - (cb->nZeroBitPlanes + cb->len + *touched); if (shift2 > 0) { cover(74); if (val < 0) { val = (val << shift2) - (1 << (shift2 - 1)); } else { val = (val << shift2) + (1 << (shift2 - 1)); } } else { cover(75); val >>= -shift2; } if (qStyle == 0) { cover(76); if (tileComp->transform == 0) { val &= -1 << fracBits; } } else { cover(77); val = (int)((double)val * mu); } } *coeff = val; } } ++cb; } } } //----- inverse transform // compute the subband bounds: // 0 nx1 nx2 // | | | // v v v // +----+----+ // | LL | HL | <- 0 // +----+----+ // | LH | HH | <- ny1 // +----+----+ // <- ny2 nx1 = precinct->subbands[1].x1 - precinct->subbands[1].x0; nx2 = nx1 + precinct->subbands[0].x1 - precinct->subbands[0].x0; ny1 = precinct->subbands[0].y1 - precinct->subbands[0].y0; ny2 = ny1 + precinct->subbands[1].y1 - precinct->subbands[1].y0; // horizontal (row) transforms if (r == tileComp->nDecompLevels) { offset = 3 + (tileComp->x0 & 1); } else { offset = 3 + (tileComp->resLevels[r+1].x0 & 1); } for (y = 0, dataPtr = tileComp->data; y < ny2; ++y, dataPtr += tileComp->w) { if (precinct->subbands[0].x0 == precinct->subbands[1].x0) { // fetch LL/LH for (x = 0, bufPtr = tileComp->buf + offset; x < nx1; ++x, bufPtr += 2) { *bufPtr = dataPtr[x]; } // fetch HL/HH for (x = nx1, bufPtr = tileComp->buf + offset + 1; x < nx2; ++x, bufPtr += 2) { *bufPtr = dataPtr[x]; } } else { // fetch LL/LH for (x = 0, bufPtr = tileComp->buf + offset + 1; x < nx1; ++x, bufPtr += 2) { *bufPtr = dataPtr[x]; } // fetch HL/HH for (x = nx1, bufPtr = tileComp->buf + offset; x < nx2; ++x, bufPtr += 2) { *bufPtr = dataPtr[x]; } } inverseTransform1D(tileComp, tileComp->buf, offset, nx2); for (x = 0, bufPtr = tileComp->buf + offset; x < nx2; ++x, ++bufPtr) { dataPtr[x] = *bufPtr; } } // vertical (column) transforms if (r == tileComp->nDecompLevels) { offset = 3 + (tileComp->y0 & 1); } else { offset = 3 + (tileComp->resLevels[r+1].y0 & 1); } for (x = 0, dataPtr = tileComp->data; x < nx2; ++x, ++dataPtr) { if (precinct->subbands[1].y0 == precinct->subbands[0].y0) { // fetch LL/HL for (y = 0, bufPtr = tileComp->buf + offset; y < ny1; ++y, bufPtr += 2) { *bufPtr = dataPtr[y * tileComp->w]; } // fetch LH/HH for (y = ny1, bufPtr = tileComp->buf + offset + 1; y < ny2; ++y, bufPtr += 2) { *bufPtr = dataPtr[y * tileComp->w]; } } else { // fetch LL/HL for (y = 0, bufPtr = tileComp->buf + offset + 1; y < ny1; ++y, bufPtr += 2) { *bufPtr = dataPtr[y * tileComp->w]; } // fetch LH/HH for (y = ny1, bufPtr = tileComp->buf + offset; y < ny2; ++y, bufPtr += 2) { *bufPtr = dataPtr[y * tileComp->w]; } } inverseTransform1D(tileComp, tileComp->buf, offset, ny2); for (y = 0, bufPtr = tileComp->buf + offset; y < ny2; ++y, ++bufPtr) { dataPtr[y * tileComp->w] = *bufPtr; } } } void JPXStream::inverseTransform1D(JPXTileComp *tileComp, int *data, Guint offset, Guint n) { Guint end, i; //----- special case for length = 1 if (n == 1) { cover(79); if (offset == 4) { cover(104); *data >>= 1; } } else { cover(80); end = offset + n; //----- extend right data[end] = data[end - 2]; if (n == 2) { cover(81); data[end+1] = data[offset + 1]; data[end+2] = data[offset]; data[end+3] = data[offset + 1]; } else { cover(82); data[end+1] = data[end - 3]; if (n == 3) { cover(105); data[end+2] = data[offset + 1]; data[end+3] = data[offset + 2]; } else { cover(106); data[end+2] = data[end - 4]; if (n == 4) { cover(107); data[end+3] = data[offset + 1]; } else { cover(108); data[end+3] = data[end - 5]; } } } //----- extend left data[offset - 1] = data[offset + 1]; data[offset - 2] = data[offset + 2]; data[offset - 3] = data[offset + 3]; if (offset == 4) { cover(83); data[0] = data[offset + 4]; } //----- 9-7 irreversible filter if (tileComp->transform == 0) { cover(84); // step 1 (even) for (i = 1; i <= end + 2; i += 2) { data[i] = (int)(idwtKappa * data[i]); } // step 2 (odd) for (i = 0; i <= end + 3; i += 2) { data[i] = (int)(idwtIKappa * data[i]); } // step 3 (even) for (i = 1; i <= end + 2; i += 2) { data[i] = (int)(data[i] - idwtDelta * (data[i-1] + data[i+1])); } // step 4 (odd) for (i = 2; i <= end + 1; i += 2) { data[i] = (int)(data[i] - idwtGamma * (data[i-1] + data[i+1])); } // step 5 (even) for (i = 3; i <= end; i += 2) { data[i] = (int)(data[i] - idwtBeta * (data[i-1] + data[i+1])); } // step 6 (odd) for (i = 4; i <= end - 1; i += 2) { data[i] = (int)(data[i] - idwtAlpha * (data[i-1] + data[i+1])); } //----- 5-3 reversible filter } else { cover(85); // step 1 (even) for (i = 3; i <= end; i += 2) { data[i] -= (data[i-1] + data[i+1] + 2) >> 2; } // step 2 (odd) for (i = 4; i < end; i += 2) { data[i] += (data[i-1] + data[i+1]) >> 1; } } } } // Inverse multi-component transform and DC level shift. This also // converts fixed point samples back to integers. GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { JPXTileComp *tileComp; int coeff, d0, d1, d2, t, minVal, maxVal, zeroVal; int *dataPtr; Guint j, comp, x, y; //----- inverse multi-component transform if (tile->multiComp == 1) { cover(86); if (img.nComps < 3 || tile->tileComps[0].hSep != tile->tileComps[1].hSep || tile->tileComps[0].vSep != tile->tileComps[1].vSep || tile->tileComps[1].hSep != tile->tileComps[2].hSep || tile->tileComps[1].vSep != tile->tileComps[2].vSep) { return gFalse; } // inverse irreversible multiple component transform if (tile->tileComps[0].transform == 0) { cover(87); j = 0; for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { d0 = tile->tileComps[0].data[j]; d1 = tile->tileComps[1].data[j]; d2 = tile->tileComps[2].data[j]; tile->tileComps[0].data[j] = (int)(d0 + 1.402 * d2 + 0.5); tile->tileComps[1].data[j] = (int)(d0 - 0.34413 * d1 - 0.71414 * d2 + 0.5); tile->tileComps[2].data[j] = (int)(d0 + 1.772 * d1 + 0.5); ++j; } } // inverse reversible multiple component transform } else { cover(88); j = 0; for (y = 0; y < tile->tileComps[0].y1 - tile->tileComps[0].y0; ++y) { for (x = 0; x < tile->tileComps[0].x1 - tile->tileComps[0].x0; ++x) { d0 = tile->tileComps[0].data[j]; d1 = tile->tileComps[1].data[j]; d2 = tile->tileComps[2].data[j]; tile->tileComps[1].data[j] = t = d0 - ((d2 + d1) >> 2); tile->tileComps[0].data[j] = d2 + t; tile->tileComps[2].data[j] = d1 + t; ++j; } } } } //----- DC level shift for (comp = 0; comp < img.nComps; ++comp) { tileComp = &tile->tileComps[comp]; // signed: clip if (tileComp->sgned) { cover(89); minVal = -(1 << (tileComp->prec - 1)); maxVal = (1 << (tileComp->prec - 1)) - 1; dataPtr = tileComp->data; for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { coeff = *dataPtr; if (tileComp->transform == 0) { cover(109); coeff >>= fracBits; } if (coeff < minVal) { cover(110); coeff = minVal; } else if (coeff > maxVal) { cover(111); coeff = maxVal; } *dataPtr++ = coeff; } } // unsigned: inverse DC level shift and clip } else { cover(90); maxVal = (1 << tileComp->prec) - 1; zeroVal = 1 << (tileComp->prec - 1); dataPtr = tileComp->data; for (y = 0; y < tileComp->y1 - tileComp->y0; ++y) { for (x = 0; x < tileComp->x1 - tileComp->x0; ++x) { coeff = *dataPtr; if (tileComp->transform == 0) { cover(112); coeff >>= fracBits; } coeff += zeroVal; if (coeff < 0) { cover(113); coeff = 0; } else if (coeff > maxVal) { cover(114); coeff = maxVal; } *dataPtr++ = coeff; } } } } return gTrue; } GBool JPXStream::readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen) { Guint len, lenH; if (!readULong(&len) || !readULong(boxType)) { return gFalse; } if (len == 1) { if (!readULong(&lenH) || !readULong(&len)) { return gFalse; } if (lenH) { error(errSyntaxError, getPos(), "JPX stream contains a box larger than 2^32 bytes"); return gFalse; } *boxLen = len; *dataLen = len - 16; } else if (len == 0) { *boxLen = 0; *dataLen = 0; } else { *boxLen = len; *dataLen = len - 8; } return gTrue; } int JPXStream::readMarkerHdr(int *segType, Guint *segLen) { int c; do { do { if ((c = bufStr->getChar()) == EOF) { return gFalse; } } while (c != 0xff); do { if ((c = bufStr->getChar()) == EOF) { return gFalse; } } while (c == 0xff); } while (c == 0x00); *segType = c; if ((c >= 0x30 && c <= 0x3f) || c == 0x4f || c == 0x92 || c == 0x93 || c == 0xd9) { *segLen = 0; return gTrue; } return readUWord(segLen); } GBool JPXStream::readUByte(Guint *x) { int c0; if ((c0 = bufStr->getChar()) == EOF) { return gFalse; } *x = (Guint)c0; return gTrue; } GBool JPXStream::readByte(int *x) { int c0; if ((c0 = bufStr->getChar()) == EOF) { return gFalse; } *x = c0; if (c0 & 0x80) { *x |= -1 - 0xff; } return gTrue; } GBool JPXStream::readUWord(Guint *x) { int c0, c1; if ((c0 = bufStr->getChar()) == EOF || (c1 = bufStr->getChar()) == EOF) { return gFalse; } *x = (Guint)((c0 << 8) | c1); return gTrue; } GBool JPXStream::readULong(Guint *x) { int c0, c1, c2, c3; if ((c0 = bufStr->getChar()) == EOF || (c1 = bufStr->getChar()) == EOF || (c2 = bufStr->getChar()) == EOF || (c3 = bufStr->getChar()) == EOF) { return gFalse; } *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); return gTrue; } GBool JPXStream::readNBytes(int nBytes, GBool signd, int *x) { int y, c, i; y = 0; for (i = 0; i < nBytes; ++i) { if ((c = bufStr->getChar()) == EOF) { return gFalse; } y = (y << 8) + c; } if (signd) { if (y & (1 << (8 * nBytes - 1))) { y |= -1 << (8 * nBytes); } } *x = y; return gTrue; } void JPXStream::startBitBuf(Guint byteCountA) { bitBufLen = 0; bitBufSkip = gFalse; byteCount = byteCountA; } GBool JPXStream::readBits(int nBits, Guint *x) { int c; while (bitBufLen < nBits) { if (byteCount == 0 || (c = bufStr->getChar()) == EOF) { return gFalse; } --byteCount; if (bitBufSkip) { bitBuf = (bitBuf << 7) | (c & 0x7f); bitBufLen += 7; } else { bitBuf = (bitBuf << 8) | (c & 0xff); bitBufLen += 8; } bitBufSkip = c == 0xff; } *x = (bitBuf >> (bitBufLen - nBits)) & ((1 << nBits) - 1); bitBufLen -= nBits; return gTrue; } void JPXStream::skipSOP() { int i; // SOP occurs at the start of the packet header, so we don't need to // worry about bit-stuff prior to it if (byteCount >= 6 && bufStr->lookChar(0) == 0xff && bufStr->lookChar(1) == 0x91) { for (i = 0; i < 6; ++i) { bufStr->getChar(); } byteCount -= 6; bitBufLen = 0; bitBufSkip = gFalse; } } void JPXStream::skipEPH() { int i, k; k = bitBufSkip ? 1 : 0; if (byteCount >= (Guint)(k + 2) && bufStr->lookChar(k) == 0xff && bufStr->lookChar(k + 1) == 0x92) { for (i = 0; i < k + 2; ++i) { bufStr->getChar(); } byteCount -= k + 2; bitBufLen = 0; bitBufSkip = gFalse; } } Guint JPXStream::finishBitBuf() { if (bitBufSkip) { bufStr->getChar(); --byteCount; } return byteCount; } xpdf-3.03/xpdf/pdfdetach.cc0000644000076400007640000001274011622305345015111 0ustar dereknderekn//======================================================================== // // pdfdetach.cc // // Copyright 2010 Glyph & Cog, LLC // //======================================================================== #include #include #include "gtypes.h" #include "gmem.h" #include "parseargs.h" #include "GlobalParams.h" #include "PDFDoc.h" #include "CharTypes.h" #include "UnicodeMap.h" #include "Error.h" #include "config.h" static GBool doList = gFalse; static int saveNum = 0; static GBool saveAll = gFalse; static char savePath[1024] = ""; static char textEncName[128] = ""; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-list", argFlag, &doList, 0, "list all embedded files"}, {"-save", argInt, &saveNum, 0, "save the specified embedded file"}, {"-saveall", argFlag, &saveAll, 0, "save all embedded files"}, {"-o", argString, savePath, sizeof(savePath), "file name for the saved embedded file"}, {"-enc", argString, textEncName, sizeof(textEncName), "output text encoding name"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { GString *fileName; UnicodeMap *uMap; GString *ownerPW, *userPW; PDFDoc *doc; Unicode *name; char uBuf[8]; char path[1024]; char *p; GBool ok; int exitCode; int nFiles, nameLen, n, i, j; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if ((doList ? 1 : 0) + ((saveNum != 0) ? 1 : 0) + (saveAll ? 1 : 0) != 1) { ok = gFalse; } if (!ok || argc != 2 || printVersion || printHelp) { fprintf(stderr, "pdfdetach version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdfdetach", "", argDesc); } goto err0; } fileName = new GString(argv[1]); // read config file globalParams = new GlobalParams(cfgFileName); if (textEncName[0]) { globalParams->setTextEncoding(textEncName); } // get mapping to output encoding if (!(uMap = globalParams->getTextEncoding())) { error(errConfig, -1, "Couldn't get text encoding"); delete fileName; goto err1; } // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err2; } nFiles = doc->getNumEmbeddedFiles(); // list embedded files if (doList) { printf("%d embedded files\n", nFiles); for (i = 0; i < nFiles; ++i) { printf("%d: ", i+1); name = doc->getEmbeddedFileName(i); nameLen = doc->getEmbeddedFileNameLength(i); for (j = 0; j < nameLen; ++j) { n = uMap->mapUnicode(name[j], uBuf, sizeof(uBuf)); fwrite(uBuf, 1, n, stdout); } fputc('\n', stdout); } // save all embedded files } else if (saveAll) { for (i = 0; i < nFiles; ++i) { if (savePath[0]) { n = strlen(savePath); if (n > (int)sizeof(path) - 2) { n = sizeof(path) - 2; } memcpy(path, savePath, n); path[n] = '/'; p = path + n + 1; } else { p = path; } name = doc->getEmbeddedFileName(i); nameLen = doc->getEmbeddedFileNameLength(i); for (j = 0; j < nameLen; ++j) { n = uMap->mapUnicode(name[j], uBuf, sizeof(uBuf)); if (p + n >= path + sizeof(path)) { break; } memcpy(p, uBuf, n); p += n; } *p = '\0'; if (!doc->saveEmbeddedFile(i, path)) { error(errIO, -1, "Error saving embedded file as '{0:s}'", p); exitCode = 2; goto err2; } } // save an embedded file } else { if (saveNum < 1 || saveNum > nFiles) { error(errCommandLine, -1, "Invalid file number"); goto err2; } if (savePath[0]) { p = savePath; } else { name = doc->getEmbeddedFileName(saveNum - 1); nameLen = doc->getEmbeddedFileNameLength(saveNum - 1); p = path; for (j = 0; j < nameLen; ++j) { n = uMap->mapUnicode(name[j], uBuf, sizeof(uBuf)); if (p + n >= path + sizeof(path)) { break; } memcpy(p, uBuf, n); p += n; } *p = '\0'; p = path; } if (!doc->saveEmbeddedFile(saveNum - 1, p)) { error(errIO, -1, "Error saving embedded file as '{0:s}'", p); exitCode = 2; goto err2; } } exitCode = 0; // clean up err2: uMap->decRefCnt(); delete doc; err1: delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } xpdf-3.03/xpdf/NameToCharCode.cc0000644000076400007640000000417311622305345015744 0ustar dereknderekn//======================================================================== // // NameToCharCode.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "NameToCharCode.h" //------------------------------------------------------------------------ struct NameToCharCodeEntry { char *name; CharCode c; }; //------------------------------------------------------------------------ NameToCharCode::NameToCharCode() { int i; size = 31; len = 0; tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (i = 0; i < size; ++i) { tab[i].name = NULL; } } NameToCharCode::~NameToCharCode() { int i; for (i = 0; i < size; ++i) { if (tab[i].name) { gfree(tab[i].name); } } gfree(tab); } void NameToCharCode::add(const char *name, CharCode c) { NameToCharCodeEntry *oldTab; int h, i, oldSize; // expand the table if necessary if (len >= size / 2) { oldSize = size; oldTab = tab; size = 2*size + 1; tab = (NameToCharCodeEntry *)gmallocn(size, sizeof(NameToCharCodeEntry)); for (h = 0; h < size; ++h) { tab[h].name = NULL; } for (i = 0; i < oldSize; ++i) { if (oldTab[i].name) { h = hash(oldTab[i].name); while (tab[h].name) { if (++h == size) { h = 0; } } tab[h] = oldTab[i]; } } gfree(oldTab); } // add the new name h = hash(name); while (tab[h].name && strcmp(tab[h].name, name)) { if (++h == size) { h = 0; } } if (!tab[h].name) { tab[h].name = copyString(name); } tab[h].c = c; ++len; } CharCode NameToCharCode::lookup(const char *name) { int h; h = hash(name); while (tab[h].name) { if (!strcmp(tab[h].name, name)) { return tab[h].c; } if (++h == size) { h = 0; } } return 0; } int NameToCharCode::hash(const char *name) { const char *p; unsigned int h; h = 0; for (p = name; *p; ++p) { h = 17 * h + (int)(*p & 0xff); } return (int)(h % size); } xpdf-3.03/xpdf/CMap.cc0000644000076400007640000002427411622305345014014 0ustar dereknderekn//======================================================================== // // CMap.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include "gmem.h" #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" #include "PSTokenizer.h" #include "Object.h" #include "Stream.h" #include "CMap.h" //------------------------------------------------------------------------ struct CMapVectorEntry { GBool isVector; union { CMapVectorEntry *vector; CID cid; }; }; //------------------------------------------------------------------------ static int getCharFromFile(void *data) { return fgetc((FILE *)data); } static int getCharFromStream(void *data) { return ((Stream *)data)->getChar(); } //------------------------------------------------------------------------ CMap *CMap::parse(CMapCache *cache, GString *collectionA, Object *obj) { CMap *cMap; GString *cMapNameA; if (obj->isName()) { cMapNameA = new GString(obj->getName()); if (!(cMap = globalParams->getCMap(collectionA, cMapNameA))) { error(errSyntaxError, -1, "Unknown CMap '{0:t}' for character collection '{1:t}'", cMapNameA, collectionA); } delete cMapNameA; } else if (obj->isStream()) { if (!(cMap = CMap::parse(NULL, collectionA, obj->getStream()))) { error(errSyntaxError, -1, "Invalid CMap in Type 0 font"); } } else { error(errSyntaxError, -1, "Invalid Encoding in Type 0 font"); return NULL; } return cMap; } CMap *CMap::parse(CMapCache *cache, GString *collectionA, GString *cMapNameA) { FILE *f; CMap *cMap; if (!(f = globalParams->findCMapFile(collectionA, cMapNameA))) { // Check for an identity CMap. if (!cMapNameA->cmp("Identity") || !cMapNameA->cmp("Identity-H")) { return new CMap(collectionA->copy(), cMapNameA->copy(), 0); } if (!cMapNameA->cmp("Identity-V")) { return new CMap(collectionA->copy(), cMapNameA->copy(), 1); } error(errSyntaxError, -1, "Couldn't find '{0:t}' CMap file for '{1:t}' collection", cMapNameA, collectionA); return NULL; } cMap = new CMap(collectionA->copy(), cMapNameA->copy()); cMap->parse2(cache, &getCharFromFile, f); fclose(f); return cMap; } CMap *CMap::parse(CMapCache *cache, GString *collectionA, Stream *str) { Object obj1; CMap *cMap; cMap = new CMap(collectionA->copy(), NULL); if (!str->getDict()->lookup("UseCMap", &obj1)->isNull()) { cMap->useCMap(cache, &obj1); } obj1.free(); str->reset(); cMap->parse2(cache, &getCharFromStream, str); str->close(); return cMap; } void CMap::parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data) { PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int n1, n2, n3; Guint start, end, code; pst = new PSTokenizer(getCharFunc, data); pst->getToken(tok1, sizeof(tok1), &n1); while (pst->getToken(tok2, sizeof(tok2), &n2)) { if (!strcmp(tok2, "usecmap")) { if (tok1[0] == '/') { useCMap(cache, tok1 + 1); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok1, "/WMode")) { wMode = atoi(tok2); pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "begincidchar")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endcidchar")) { break; } if (!pst->getToken(tok2, sizeof(tok2), &n2) || !strcmp(tok2, "endcidchar")) { error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap"); break; } if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && n1 >= 4 && (n1 & 1) == 0)) { error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap"); continue; } tok1[n1 - 1] = '\0'; if (sscanf(tok1 + 1, "%x", &code) != 1) { error(errSyntaxError, -1, "Illegal entry in cidchar block in CMap"); continue; } n1 = (n1 - 2) / 2; addCIDs(code, code, n1, (CID)atoi(tok2)); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "begincidrange")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endcidrange")) { break; } if (!pst->getToken(tok2, sizeof(tok2), &n2) || !strcmp(tok2, "endcidrange") || !pst->getToken(tok3, sizeof(tok3), &n3) || !strcmp(tok3, "endcidrange")) { error(errSyntaxError, -1, "Illegal entry in cidrange block in CMap"); break; } if (tok1[0] == '<' && tok2[0] == '<' && n1 == n2 && n1 >= 4 && (n1 & 1) == 0) { tok1[n1 - 1] = tok2[n1 - 1] = '\0'; sscanf(tok1 + 1, "%x", &start); sscanf(tok2 + 1, "%x", &end); n1 = (n1 - 2) / 2; addCIDs(start, end, n1, (CID)atoi(tok3)); } } pst->getToken(tok1, sizeof(tok1), &n1); } else { strcpy(tok1, tok2); } } delete pst; } CMap::CMap(GString *collectionA, GString *cMapNameA) { int i; collection = collectionA; cMapName = cMapNameA; isIdent = gFalse; wMode = 0; vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (i = 0; i < 256; ++i) { vector[i].isVector = gFalse; vector[i].cid = 0; } refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) { collection = collectionA; cMapName = cMapNameA; isIdent = gTrue; wMode = wModeA; vector = NULL; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } void CMap::useCMap(CMapCache *cache, char *useName) { GString *useNameStr; CMap *subCMap; useNameStr = new GString(useName); // if cache is non-NULL, we already have a lock, and we can use // CMapCache::getCMap() directly; otherwise, we need to use // GlobalParams::getCMap() in order to acqure the lock need to use // GlobalParams::getCMap if (cache) { subCMap = cache->getCMap(collection, useNameStr); } else { subCMap = globalParams->getCMap(collection, useNameStr); } delete useNameStr; if (!subCMap) { return; } isIdent = subCMap->isIdent; if (subCMap->vector) { copyVector(vector, subCMap->vector); } subCMap->decRefCnt(); } void CMap::useCMap(CMapCache *cache, Object *obj) { CMap *subCMap; subCMap = CMap::parse(cache, collection, obj); if (!subCMap) { return; } isIdent = subCMap->isIdent; if (subCMap->vector) { copyVector(vector, subCMap->vector); } subCMap->decRefCnt(); } void CMap::copyVector(CMapVectorEntry *dest, CMapVectorEntry *src) { int i, j; for (i = 0; i < 256; ++i) { if (src[i].isVector) { if (!dest[i].isVector) { dest[i].isVector = gTrue; dest[i].vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { dest[i].vector[j].isVector = gFalse; dest[i].vector[j].cid = 0; } } copyVector(dest[i].vector, src[i].vector); } else { if (dest[i].isVector) { error(errSyntaxError, -1, "Collision in usecmap"); } else { dest[i].cid = src[i].cid; } } } } void CMap::addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID) { CMapVectorEntry *vec; CID cid; int byte; Guint i, j; vec = vector; for (i = nBytes - 1; i >= 1; --i) { byte = (start >> (8 * i)) & 0xff; if (!vec[byte].isVector) { vec[byte].isVector = gTrue; vec[byte].vector = (CMapVectorEntry *)gmallocn(256, sizeof(CMapVectorEntry)); for (j = 0; j < 256; ++j) { vec[byte].vector[j].isVector = gFalse; vec[byte].vector[j].cid = 0; } } vec = vec[byte].vector; } cid = firstCID; for (byte = (int)(start & 0xff); byte <= (int)(end & 0xff); ++byte) { if (vec[byte].isVector) { error(errSyntaxError, -1, "Invalid CID ({0:x} - {1:x} [{2:d} bytes]) in CMap", start, end, nBytes); } else { vec[byte].cid = cid; } ++cid; } } CMap::~CMap() { delete collection; if (cMapName) { delete cMapName; } if (vector) { freeCMapVector(vector); } #if MULTITHREADED gDestroyMutex(&mutex); #endif } void CMap::freeCMapVector(CMapVectorEntry *vec) { int i; for (i = 0; i < 256; ++i) { if (vec[i].isVector) { freeCMapVector(vec[i].vector); } } gfree(vec); } void CMap::incRefCnt() { #if MULTITHREADED gLockMutex(&mutex); #endif ++refCnt; #if MULTITHREADED gUnlockMutex(&mutex); #endif } void CMap::decRefCnt() { GBool done; #if MULTITHREADED gLockMutex(&mutex); #endif done = --refCnt == 0; #if MULTITHREADED gUnlockMutex(&mutex); #endif if (done) { delete this; } } GBool CMap::match(GString *collectionA, GString *cMapNameA) { return !collection->cmp(collectionA) && !cMapName->cmp(cMapNameA); } CID CMap::getCID(char *s, int len, CharCode *c, int *nUsed) { CMapVectorEntry *vec; CharCode cc; int n, i; vec = vector; cc = 0; n = 0; while (vec && n < len) { i = s[n++] & 0xff; cc = (cc << 8) | i; if (!vec[i].isVector) { *c = cc; *nUsed = n; return vec[i].cid; } vec = vec[i].vector; } if (isIdent && len >= 2) { // identity CMap *nUsed = 2; *c = cc = ((s[0] & 0xff) << 8) + (s[1] & 0xff); return cc; } *nUsed = 1; *c = s[0] & 0xff; return 0; } //------------------------------------------------------------------------ CMapCache::CMapCache() { int i; for (i = 0; i < cMapCacheSize; ++i) { cache[i] = NULL; } } CMapCache::~CMapCache() { int i; for (i = 0; i < cMapCacheSize; ++i) { if (cache[i]) { cache[i]->decRefCnt(); } } } CMap *CMapCache::getCMap(GString *collection, GString *cMapName) { CMap *cmap; int i, j; if (cache[0] && cache[0]->match(collection, cMapName)) { cache[0]->incRefCnt(); return cache[0]; } for (i = 1; i < cMapCacheSize; ++i) { if (cache[i] && cache[i]->match(collection, cMapName)) { cmap = cache[i]; for (j = i; j >= 1; --j) { cache[j] = cache[j - 1]; } cache[0] = cmap; cmap->incRefCnt(); return cmap; } } if ((cmap = CMap::parse(this, collection, cMapName))) { if (cache[cMapCacheSize - 1]) { cache[cMapCacheSize - 1]->decRefCnt(); } for (j = cMapCacheSize - 1; j >= 1; --j) { cache[j] = cache[j - 1]; } cache[0] = cmap; cmap->incRefCnt(); return cmap; } return NULL; } xpdf-3.03/xpdf/pdfimages.cc0000644000076400007640000000745411622305345015134 0ustar dereknderekn//======================================================================== // // pdfimages.cc // // Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include #include #include #include "parseargs.h" #include "GString.h" #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "Stream.h" #include "Array.h" #include "Dict.h" #include "XRef.h" #include "Catalog.h" #include "Page.h" #include "PDFDoc.h" #include "ImageOutputDev.h" #include "Error.h" #include "config.h" static int firstPage = 1; static int lastPage = 0; static GBool dumpJPEG = gFalse; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to convert"}, {"-l", argInt, &lastPage, 0, "last page to convert"}, {"-j", argFlag, &dumpJPEG, 0, "write JPEG images as JPEG files"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; char *imgRoot; GString *ownerPW, *userPW; ImageOutputDev *imgOut; GBool ok; int exitCode; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || argc != 3 || printVersion || printHelp) { fprintf(stderr, "pdfimages version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdfimages", " ", argDesc); } goto err0; } fileName = new GString(argv[1]); imgRoot = argv[2]; // read config file globalParams = new GlobalParams(cfgFileName); if (quiet) { globalParams->setErrQuiet(quiet); } // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err1; } // check for copy permission if (!doc->okToCopy()) { error(errNotAllowed, -1, "Copying of images from this document is not allowed."); exitCode = 3; goto err1; } // get page range if (firstPage < 1) firstPage = 1; if (lastPage < 1 || lastPage > doc->getNumPages()) lastPage = doc->getNumPages(); // write image files imgOut = new ImageOutputDev(imgRoot, dumpJPEG); if (imgOut->isOk()) { doc->displayPages(imgOut, firstPage, lastPage, 72, 72, 0, gFalse, gTrue, gFalse); } delete imgOut; exitCode = 0; // clean up err1: delete doc; delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } xpdf-3.03/xpdf/XPDFCore.cc0000644000076400007640000013422311622305345014542 0ustar dereknderekn//======================================================================== // // XPDFCore.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gmem.h" #include "GString.h" #include "GList.h" #include "Error.h" #include "GlobalParams.h" #include "PDFDoc.h" #include "Link.h" #include "ErrorCodes.h" #include "GfxState.h" #include "CoreOutputDev.h" #include "PSOutputDev.h" #include "TextOutputDev.h" #include "SplashBitmap.h" #include "SplashPattern.h" #include "XPDFApp.h" #include "XPDFCore.h" // these macro defns conflict with xpdf's Object class #ifdef LESSTIF_VERSION #undef XtDisplay #undef XtScreen #undef XtWindow #undef XtParent #undef XtIsRealized #endif //------------------------------------------------------------------------ // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } //------------------------------------------------------------------------ GString *XPDFCore::currentSelection = NULL; XPDFCore *XPDFCore::currentSelectionOwner = NULL; Atom XPDFCore::targetsAtom; //------------------------------------------------------------------------ // XPDFCoreTile //------------------------------------------------------------------------ class XPDFCoreTile: public PDFCoreTile { public: XPDFCoreTile(int xDestA, int yDestA); virtual ~XPDFCoreTile(); XImage *image; }; XPDFCoreTile::XPDFCoreTile(int xDestA, int yDestA): PDFCoreTile(xDestA, yDestA) { image = NULL; } XPDFCoreTile::~XPDFCoreTile() { if (image) { gfree(image->data); image->data = NULL; XDestroyImage(image); } } //------------------------------------------------------------------------ // XPDFCore //------------------------------------------------------------------------ XPDFCore::XPDFCore(Widget shellA, Widget parentWidgetA, SplashColorPtr paperColorA, Gulong paperPixelA, Gulong mattePixelA, GBool fullScreenA, GBool reverseVideoA, GBool installCmap, int rgbCubeSizeA): PDFCore(splashModeRGB8, 4, reverseVideoA, paperColorA, !fullScreenA) { GString *initialZoom; shell = shellA; parentWidget = parentWidgetA; display = XtDisplay(parentWidget); screenNum = XScreenNumberOfScreen(XtScreen(parentWidget)); targetsAtom = XInternAtom(display, "TARGETS", False); paperPixel = paperPixelA; mattePixel = mattePixelA; fullScreen = fullScreenA; setupX(installCmap, rgbCubeSizeA); scrolledWin = NULL; hScrollBar = NULL; vScrollBar = NULL; drawAreaFrame = NULL; drawArea = NULL; // get the initial zoom value if (fullScreen) { zoom = zoomPage; } else { initialZoom = globalParams->getInitialZoom(); if (!initialZoom->cmp("page")) { zoom = zoomPage; } else if (!initialZoom->cmp("width")) { zoom = zoomWidth; } else { zoom = atoi(initialZoom->getCString()); if (zoom <= 0) { zoom = defZoom; } } delete initialZoom; } linkAction = NULL; panning = gFalse; updateCbk = NULL; actionCbk = NULL; keyPressCbk = NULL; mouseCbk = NULL; // optional features default to on hyperlinksEnabled = gTrue; selectEnabled = gTrue; // do X-specific initialization and create the widgets initWindow(); initPasswordDialog(); } XPDFCore::~XPDFCore() { if (currentSelectionOwner == this && currentSelection) { delete currentSelection; currentSelection = NULL; currentSelectionOwner = NULL; } if (drawAreaGC) { XFreeGC(display, drawAreaGC); } if (scrolledWin) { XtDestroyWidget(scrolledWin); } if (busyCursor) { XFreeCursor(display, busyCursor); } if (linkCursor) { XFreeCursor(display, linkCursor); } if (selectCursor) { XFreeCursor(display, selectCursor); } } //------------------------------------------------------------------------ // loadFile / displayPage / displayDest //------------------------------------------------------------------------ int XPDFCore::loadFile(GString *fileName, GString *ownerPassword, GString *userPassword) { int err; err = PDFCore::loadFile(fileName, ownerPassword, userPassword); if (err == errNone) { // save the modification time modTime = getModTime(doc->getFileName()->getCString()); // update the parent window if (updateCbk) { (*updateCbk)(updateCbkData, doc->getFileName(), -1, doc->getNumPages(), NULL); } } return err; } int XPDFCore::loadFile(BaseStream *stream, GString *ownerPassword, GString *userPassword) { int err; err = PDFCore::loadFile(stream, ownerPassword, userPassword); if (err == errNone) { // no file modTime = 0; // update the parent window if (updateCbk) { (*updateCbk)(updateCbkData, doc->getFileName(), -1, doc->getNumPages(), NULL); } } return err; } void XPDFCore::loadDoc(PDFDoc *docA) { PDFCore::loadDoc(docA); // save the modification time if (doc->getFileName()) { modTime = getModTime(doc->getFileName()->getCString()); } // update the parent window if (updateCbk) { (*updateCbk)(updateCbkData, doc->getFileName(), -1, doc->getNumPages(), NULL); } } void XPDFCore::resizeToPage(int pg) { Dimension width, height; double width1, height1; Dimension topW, topH, topBorder, daW, daH; Dimension displayW, displayH; displayW = DisplayWidth(display, screenNum); displayH = DisplayHeight(display, screenNum); if (fullScreen) { width = displayW; height = displayH; } else { if (!doc || pg <= 0 || pg > doc->getNumPages()) { width1 = 612; height1 = 792; } else if (doc->getPageRotate(pg) == 90 || doc->getPageRotate(pg) == 270) { width1 = doc->getPageCropHeight(pg); height1 = doc->getPageCropWidth(pg); } else { width1 = doc->getPageCropWidth(pg); height1 = doc->getPageCropHeight(pg); } if (zoom == zoomPage || zoom == zoomWidth) { width = (Dimension)(width1 * 0.01 * defZoom + 0.5); height = (Dimension)(height1 * 0.01 * defZoom + 0.5); } else { width = (Dimension)(width1 * 0.01 * zoom + 0.5); height = (Dimension)(height1 * 0.01 * zoom + 0.5); } if (continuousMode) { height += continuousModePageSpacing; } if (width > displayW - 100) { width = displayW - 100; } if (height > displayH - 100) { height = displayH - 100; } } if (XtIsRealized(shell)) { XtVaGetValues(shell, XmNwidth, &topW, XmNheight, &topH, XmNborderWidth, &topBorder, NULL); XtVaGetValues(drawArea, XmNwidth, &daW, XmNheight, &daH, NULL); XtVaSetValues(shell, XmNwidth, width + (topW - daW), XmNheight, height + (topH - daH), NULL); } else { XtVaSetValues(drawArea, XmNwidth, width, XmNheight, height, NULL); } } void XPDFCore::update(int topPageA, int scrollXA, int scrollYA, double zoomA, int rotateA, GBool force, GBool addToHist, GBool adjustScrollX) { int oldPage; oldPage = topPage; PDFCore::update(topPageA, scrollXA, scrollYA, zoomA, rotateA, force, addToHist, adjustScrollX); linkAction = NULL; if (doc && topPage != oldPage) { if (updateCbk) { (*updateCbk)(updateCbkData, NULL, topPage, -1, ""); } } } GBool XPDFCore::checkForNewFile() { time_t newModTime; if (doc->getFileName()) { newModTime = getModTime(doc->getFileName()->getCString()); if (newModTime != modTime) { modTime = newModTime; return gTrue; } } return gFalse; } //------------------------------------------------------------------------ // page/position changes //------------------------------------------------------------------------ GBool XPDFCore::gotoNextPage(int inc, GBool top) { if (!PDFCore::gotoNextPage(inc, top)) { XBell(display, 0); return gFalse; } return gTrue; } GBool XPDFCore::gotoPrevPage(int dec, GBool top, GBool bottom) { if (!PDFCore::gotoPrevPage(dec, top, bottom)) { XBell(display, 0); return gFalse; } return gTrue; } GBool XPDFCore::goForward() { if (!PDFCore::goForward()) { XBell(display, 0); return gFalse; } return gTrue; } GBool XPDFCore::goBackward() { if (!PDFCore::goBackward()) { XBell(display, 0); return gFalse; } return gTrue; } void XPDFCore::startPan(int wx, int wy) { panning = gTrue; panMX = wx; panMY = wy; } void XPDFCore::endPan(int wx, int wy) { panning = gFalse; } //------------------------------------------------------------------------ // selection //------------------------------------------------------------------------ void XPDFCore::startSelection(int wx, int wy) { int pg, x, y; takeFocus(); if (doc && doc->getNumPages() > 0) { if (selectEnabled) { if (cvtWindowToDev(wx, wy, &pg, &x, &y)) { setSelection(pg, x, y, x, y); setCursor(selectCursor); dragging = gTrue; } } } } void XPDFCore::endSelection(int wx, int wy) { int pg, x, y; GBool ok; if (doc && doc->getNumPages() > 0) { ok = cvtWindowToDev(wx, wy, &pg, &x, &y); if (dragging) { dragging = gFalse; setCursor(None); if (ok) { moveSelection(pg, x, y); } #ifndef NO_TEXT_SELECT if (selectULX != selectLRX && selectULY != selectLRY) { if (doc->okToCopy()) { copySelection(); } else { error(errNotAllowed, -1, "Copying of text from this document is not allowed."); } } #endif } } } // X's copy-and-paste mechanism is brain damaged. Xt doesn't help // any, but doesn't make it too much worse, either. Motif, on the // other hand, adds significant complexity to the mess. So here we // blow off the Motif junk and stick to plain old Xt. The next two // functions (copySelection and convertSelectionCbk) implement the // magic needed to deal with Xt's mechanism. Note that this requires // global variables (currentSelection and currentSelectionOwner). void XPDFCore::copySelection() { int pg; double ulx, uly, lrx, lry; if (!doc->okToCopy()) { return; } if (getSelection(&pg, &ulx, &uly, &lrx, &lry)) { //~ for multithreading: need a mutex here if (currentSelection) { delete currentSelection; } currentSelection = extractText(pg, ulx, uly, lrx, lry); currentSelectionOwner = this; XtOwnSelection(drawArea, XA_PRIMARY, XtLastTimestampProcessed(display), &convertSelectionCbk, NULL, NULL); } } Boolean XPDFCore::convertSelectionCbk(Widget widget, Atom *selection, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format) { Atom *array; // send back a list of supported conversion targets if (*target == targetsAtom) { if (!(array = (Atom *)XtMalloc(sizeof(Atom)))) { return False; } array[0] = XA_STRING; *value = (XtPointer)array; *type = XA_ATOM; *format = 32; *length = 1; return True; // send the selected text } else if (*target == XA_STRING) { //~ for multithreading: need a mutex here *value = XtNewString(currentSelection->getCString()); *length = currentSelection->getLength(); *type = XA_STRING; *format = 8; // 8-bit elements return True; } return False; } //------------------------------------------------------------------------ // hyperlinks //------------------------------------------------------------------------ void XPDFCore::doAction(LinkAction *action) { LinkActionKind kind; LinkDest *dest; GString *namedDest; char *s; GString *fileName, *fileName2; GString *cmd; GString *actionName; Object movieAnnot, obj1, obj2; GString *msg; int i; switch (kind = action->getKind()) { // GoTo / GoToR action case actionGoTo: case actionGoToR: if (kind == actionGoTo) { dest = NULL; namedDest = NULL; if ((dest = ((LinkGoTo *)action)->getDest())) { dest = dest->copy(); } else if ((namedDest = ((LinkGoTo *)action)->getNamedDest())) { namedDest = namedDest->copy(); } } else { dest = NULL; namedDest = NULL; if ((dest = ((LinkGoToR *)action)->getDest())) { dest = dest->copy(); } else if ((namedDest = ((LinkGoToR *)action)->getNamedDest())) { namedDest = namedDest->copy(); } s = ((LinkGoToR *)action)->getFileName()->getCString(); //~ translate path name for VMS (deal with '/') if (isAbsolutePath(s)) { fileName = new GString(s); } else { fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s); } if (loadFile(fileName) != errNone) { if (dest) { delete dest; } if (namedDest) { delete namedDest; } delete fileName; return; } delete fileName; } if (namedDest) { dest = doc->findDest(namedDest); delete namedDest; } if (dest) { displayDest(dest, zoom, rotate, gTrue); delete dest; } else { if (kind == actionGoToR) { displayPage(1, zoom, 0, gFalse, gTrue); } } break; // Launch action case actionLaunch: fileName = ((LinkLaunch *)action)->getFileName(); s = fileName->getCString(); if (!strcmp(s + fileName->getLength() - 4, ".pdf") || !strcmp(s + fileName->getLength() - 4, ".PDF")) { //~ translate path name for VMS (deal with '/') if (isAbsolutePath(s)) { fileName = fileName->copy(); } else { fileName = appendToPath(grabPath(doc->getFileName()->getCString()), s); } if (loadFile(fileName) != errNone) { delete fileName; return; } delete fileName; displayPage(1, zoom, rotate, gFalse, gTrue); } else { fileName = fileName->copy(); if (((LinkLaunch *)action)->getParams()) { fileName->append(' '); fileName->append(((LinkLaunch *)action)->getParams()); } #ifdef VMS fileName->insert(0, "spawn/nowait "); #elif defined(__EMX__) fileName->insert(0, "start /min /n "); #else fileName->append(" &"); #endif if (globalParams->getLaunchCommand()) { fileName->insert(0, ' '); fileName->insert(0, globalParams->getLaunchCommand()); system(fileName->getCString()); } else { msg = new GString("About to execute the command:\n"); msg->append(fileName); if (doQuestionDialog("Launching external application", msg)) { system(fileName->getCString()); } delete msg; } delete fileName; } break; // URI action case actionURI: if (!(cmd = globalParams->getURLCommand())) { error(errConfig, -1, "No urlCommand defined in config file"); break; } runCommand(cmd, ((LinkURI *)action)->getURI()); break; // Named action case actionNamed: actionName = ((LinkNamed *)action)->getName(); if (!actionName->cmp("NextPage")) { gotoNextPage(1, gTrue); } else if (!actionName->cmp("PrevPage")) { gotoPrevPage(1, gTrue, gFalse); } else if (!actionName->cmp("FirstPage")) { if (topPage != 1) { displayPage(1, zoom, rotate, gTrue, gTrue); } } else if (!actionName->cmp("LastPage")) { if (topPage != doc->getNumPages()) { displayPage(doc->getNumPages(), zoom, rotate, gTrue, gTrue); } } else if (!actionName->cmp("GoBack")) { goBackward(); } else if (!actionName->cmp("GoForward")) { goForward(); } else if (!actionName->cmp("Quit")) { if (actionCbk) { (*actionCbk)(actionCbkData, actionName->getCString()); } } else { error(errSyntaxError, -1, "Unknown named action: '{0:t}'", actionName); } break; // Movie action case actionMovie: if (!(cmd = globalParams->getMovieCommand())) { error(errConfig, -1, "No movieCommand defined in config file"); break; } if (((LinkMovie *)action)->hasAnnotRef()) { doc->getXRef()->fetch(((LinkMovie *)action)->getAnnotRef()->num, ((LinkMovie *)action)->getAnnotRef()->gen, &movieAnnot); } else { //~ need to use the correct page num here doc->getCatalog()->getPage(topPage)->getAnnots(&obj1); if (obj1.isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGet(i, &movieAnnot)->isDict()) { if (movieAnnot.dictLookup("Subtype", &obj2)->isName("Movie")) { obj2.free(); break; } obj2.free(); } movieAnnot.free(); } obj1.free(); } } if (movieAnnot.isDict()) { if (movieAnnot.dictLookup("Movie", &obj1)->isDict()) { if (obj1.dictLookup("F", &obj2)) { if ((fileName = LinkAction::getFileSpecName(&obj2))) { if (!isAbsolutePath(fileName->getCString())) { fileName2 = appendToPath( grabPath(doc->getFileName()->getCString()), fileName->getCString()); delete fileName; fileName = fileName2; } runCommand(cmd, fileName); delete fileName; } obj2.free(); } obj1.free(); } } movieAnnot.free(); break; // unknown action type case actionUnknown: error(errSyntaxError, -1, "Unknown link action type: '{0:t}'", ((LinkUnknown *)action)->getAction()); break; } } // Run a command, given a string with one '%s' in it, and an // string to insert in place of the '%s'. void XPDFCore::runCommand(GString *cmdFmt, GString *arg) { GString *cmd; char *s; if ((s = strstr(cmdFmt->getCString(), "%s"))) { cmd = mungeURL(arg); cmd->insert(0, cmdFmt->getCString(), s - cmdFmt->getCString()); cmd->append(s + 2); } else { cmd = cmdFmt->copy(); } #ifdef VMS cmd->insert(0, "spawn/nowait "); #elif defined(__EMX__) cmd->insert(0, "start /min /n "); #else cmd->append(" &"); #endif system(cmd->getCString()); delete cmd; } // Escape any characters in a URL which might cause problems when // calling system(). GString *XPDFCore::mungeURL(GString *url) { static const char *allowed = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "-_.~/?:@&=+,#%"; GString *newURL; char c; char buf[4]; int i; newURL = new GString(); for (i = 0; i < url->getLength(); ++i) { c = url->getChar(i); if (strchr(allowed, c)) { newURL->append(c); } else { sprintf(buf, "%%%02x", c & 0xff); newURL->append(buf); } } return newURL; } //------------------------------------------------------------------------ // find //------------------------------------------------------------------------ GBool XPDFCore::find(char *s, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly) { if (!PDFCore::find(s, caseSensitive, next, backward, wholeWord, onePageOnly)) { XBell(display, 0); return gFalse; } #ifndef NO_TEXT_SELECT copySelection(); #endif return gTrue; } GBool XPDFCore::findU(Unicode *u, int len, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly) { if (!PDFCore::findU(u, len, caseSensitive, next, backward, wholeWord, onePageOnly)) { XBell(display, 0); return gFalse; } #ifndef NO_TEXT_SELECT copySelection(); #endif return gTrue; } //------------------------------------------------------------------------ // misc access //------------------------------------------------------------------------ void XPDFCore::setBusyCursor(GBool busy) { setCursor(busy ? busyCursor : None); } void XPDFCore::takeFocus() { XmProcessTraversal(drawArea, XmTRAVERSE_CURRENT); } //------------------------------------------------------------------------ // GUI code //------------------------------------------------------------------------ void XPDFCore::setupX(GBool installCmap, int rgbCubeSizeA) { XVisualInfo visualTempl; XVisualInfo *visualList; Gulong mask; int nVisuals; XColor xcolor; XColor *xcolors; int r, g, b, n, m; GBool ok; // for some reason, querying XmNvisual doesn't work (even if done // after the window is mapped) visual = DefaultVisual(display, screenNum); XtVaGetValues(shell, XmNcolormap, &colormap, NULL); // check for TrueColor visual //~ this should scan the list, not just look at the first one visualTempl.visualid = XVisualIDFromVisual(visual); visualList = XGetVisualInfo(display, VisualIDMask, &visualTempl, &nVisuals); if (nVisuals < 1) { // this shouldn't happen XFree((XPointer)visualList); visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl, &nVisuals); } depth = visualList->depth; if (visualList->c_class == TrueColor) { trueColor = gTrue; for (mask = visualList->red_mask, rShift = 0; mask && !(mask & 1); mask >>= 1, ++rShift) ; for (rDiv = 8; mask; mask >>= 1, --rDiv) ; for (mask = visualList->green_mask, gShift = 0; mask && !(mask & 1); mask >>= 1, ++gShift) ; for (gDiv = 8; mask; mask >>= 1, --gDiv) ; for (mask = visualList->blue_mask, bShift = 0; mask && !(mask & 1); mask >>= 1, ++bShift) ; for (bDiv = 8; mask; mask >>= 1, --bDiv) ; } else { trueColor = gFalse; } XFree((XPointer)visualList); // allocate a color cube if (!trueColor) { // set colors in private colormap if (installCmap) { for (rgbCubeSize = xMaxRGBCube; rgbCubeSize >= 2; --rgbCubeSize) { m = rgbCubeSize * rgbCubeSize * rgbCubeSize; if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) { break; } } if (rgbCubeSize >= 2) { m = rgbCubeSize * rgbCubeSize * rgbCubeSize; xcolors = (XColor *)gmallocn(m, sizeof(XColor)); n = 0; for (r = 0; r < rgbCubeSize; ++r) { for (g = 0; g < rgbCubeSize; ++g) { for (b = 0; b < rgbCubeSize; ++b) { xcolors[n].pixel = colors[n]; xcolors[n].red = (r * 65535) / (rgbCubeSize - 1); xcolors[n].green = (g * 65535) / (rgbCubeSize - 1); xcolors[n].blue = (b * 65535) / (rgbCubeSize - 1); xcolors[n].flags = DoRed | DoGreen | DoBlue; ++n; } } } XStoreColors(display, colormap, xcolors, m); gfree(xcolors); } else { rgbCubeSize = 1; colors[0] = BlackPixel(display, screenNum); colors[1] = WhitePixel(display, screenNum); } // allocate colors in shared colormap } else { if (rgbCubeSize > xMaxRGBCube) { rgbCubeSize = xMaxRGBCube; } ok = gFalse; for (rgbCubeSize = rgbCubeSizeA; rgbCubeSize >= 2; --rgbCubeSize) { ok = gTrue; n = 0; for (r = 0; r < rgbCubeSize && ok; ++r) { for (g = 0; g < rgbCubeSize && ok; ++g) { for (b = 0; b < rgbCubeSize && ok; ++b) { if (n == 0) { colors[n] = BlackPixel(display, screenNum); ++n; } else { xcolor.red = (r * 65535) / (rgbCubeSize - 1); xcolor.green = (g * 65535) / (rgbCubeSize - 1); xcolor.blue = (b * 65535) / (rgbCubeSize - 1); if (XAllocColor(display, colormap, &xcolor)) { colors[n++] = xcolor.pixel; } else { ok = gFalse; } } } } } if (ok) { break; } XFreeColors(display, colormap, &colors[1], n-1, 0); } if (!ok) { rgbCubeSize = 1; colors[0] = BlackPixel(display, screenNum); colors[1] = WhitePixel(display, screenNum); } } } } void XPDFCore::initWindow() { Arg args[20]; int n; // create the cursors busyCursor = XCreateFontCursor(display, XC_watch); linkCursor = XCreateFontCursor(display, XC_hand2); selectCursor = XCreateFontCursor(display, XC_cross); currentCursor = 0; // create the scrolled window and scrollbars n = 0; XtSetArg(args[n], XmNscrollingPolicy, XmAPPLICATION_DEFINED); ++n; XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; scrolledWin = XmCreateScrolledWindow(parentWidget, "scroll", args, n); XtManageChild(scrolledWin); n = 0; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; XtSetArg(args[n], XmNminimum, 0); ++n; XtSetArg(args[n], XmNmaximum, 1); ++n; XtSetArg(args[n], XmNsliderSize, 1); ++n; XtSetArg(args[n], XmNvalue, 0); ++n; XtSetArg(args[n], XmNincrement, 1); ++n; XtSetArg(args[n], XmNpageIncrement, 1); ++n; hScrollBar = XmCreateScrollBar(scrolledWin, "hScrollBar", args, n); if (!fullScreen) { XtManageChild(hScrollBar); } XtAddCallback(hScrollBar, XmNvalueChangedCallback, &hScrollChangeCbk, (XtPointer)this); #ifndef DISABLE_SMOOTH_SCROLL XtAddCallback(hScrollBar, XmNdragCallback, &hScrollDragCbk, (XtPointer)this); #endif n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; XtSetArg(args[n], XmNminimum, 0); ++n; XtSetArg(args[n], XmNmaximum, 1); ++n; XtSetArg(args[n], XmNsliderSize, 1); ++n; XtSetArg(args[n], XmNvalue, 0); ++n; XtSetArg(args[n], XmNincrement, 1); ++n; XtSetArg(args[n], XmNpageIncrement, 1); ++n; vScrollBar = XmCreateScrollBar(scrolledWin, "vScrollBar", args, n); if (!fullScreen) { XtManageChild(vScrollBar); } XtAddCallback(vScrollBar, XmNvalueChangedCallback, &vScrollChangeCbk, (XtPointer)this); #ifndef DISABLE_SMOOTH_SCROLL XtAddCallback(vScrollBar, XmNdragCallback, &vScrollDragCbk, (XtPointer)this); #endif // create the drawing area n = 0; XtSetArg(args[n], XmNshadowType, XmSHADOW_IN); ++n; XtSetArg(args[n], XmNmarginWidth, 0); ++n; XtSetArg(args[n], XmNmarginHeight, 0); ++n; if (fullScreen) { XtSetArg(args[n], XmNshadowThickness, 0); ++n; } drawAreaFrame = XmCreateFrame(scrolledWin, "drawAreaFrame", args, n); XtManageChild(drawAreaFrame); n = 0; XtSetArg(args[n], XmNresizePolicy, XmRESIZE_ANY); ++n; XtSetArg(args[n], XmNwidth, 700); ++n; XtSetArg(args[n], XmNheight, 500); ++n; drawArea = XmCreateDrawingArea(drawAreaFrame, "drawArea", args, n); XtManageChild(drawArea); XtAddCallback(drawArea, XmNresizeCallback, &resizeCbk, (XtPointer)this); XtAddCallback(drawArea, XmNexposeCallback, &redrawCbk, (XtPointer)this); XtAddCallback(drawArea, XmNinputCallback, &inputCbk, (XtPointer)this); resizeCbk(drawArea, this, NULL); // set up mouse motion translations XtOverrideTranslations(drawArea, XtParseTranslationTable( ":DrawingAreaInput()\n" ":DrawingAreaInput()\n" ":DrawingAreaInput()\n" ":DrawingAreaInput()")); // can't create a GC until the window gets mapped drawAreaGC = NULL; } void XPDFCore::hScrollChangeCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; core->scrollTo(data->value, core->scrollY); } void XPDFCore::hScrollDragCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; core->scrollTo(data->value, core->scrollY); } void XPDFCore::vScrollChangeCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; core->scrollTo(core->scrollX, data->value); } void XPDFCore::vScrollDragCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmScrollBarCallbackStruct *data = (XmScrollBarCallbackStruct *)callData; core->scrollTo(core->scrollX, data->value); } void XPDFCore::resizeCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XEvent event; Widget top; Window rootWin; int x1, y1; Guint w1, h1, bw1, depth1; Arg args[2]; int n; Dimension w, h; int sx, sy; // find the top-most widget which has an associated window, and look // for a pending ConfigureNotify in the event queue -- if there is // one, and it specifies a different width or height, that means // we're still resizing, and we want to skip the current event for (top = core->parentWidget; XtParent(top) && XtWindow(XtParent(top)); top = XtParent(top)) ; if (XCheckTypedWindowEvent(core->display, XtWindow(top), ConfigureNotify, &event)) { XPutBackEvent(core->display, &event); XGetGeometry(core->display, event.xconfigure.window, &rootWin, &x1, &y1, &w1, &h1, &bw1, &depth1); if ((Guint)event.xconfigure.width != w1 || (Guint)event.xconfigure.height != h1) { return; } } n = 0; XtSetArg(args[n], XmNwidth, &w); ++n; XtSetArg(args[n], XmNheight, &h); ++n; XtGetValues(core->drawArea, args, n); core->drawAreaWidth = (int)w; core->drawAreaHeight = (int)h; if (core->zoom == zoomPage || core->zoom == zoomWidth) { sx = sy = -1; } else { sx = core->scrollX; sy = core->scrollY; } core->update(core->topPage, sx, sy, core->zoom, core->rotate, gTrue, gFalse, gFalse); } void XPDFCore::redrawCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData; int x, y, w, h; if (data->reason == XmCR_EXPOSE) { x = data->event->xexpose.x; y = data->event->xexpose.y; w = data->event->xexpose.width; h = data->event->xexpose.height; } else { x = 0; y = 0; w = core->drawAreaWidth; h = core->drawAreaHeight; } core->redrawWindow(x, y, w, h, gFalse); } void XPDFCore::inputCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmDrawingAreaCallbackStruct *data = (XmDrawingAreaCallbackStruct *)callData; LinkAction *action; int pg, x, y; double xu, yu; const char *s; KeySym key; GBool ok; switch (data->event->type) { case ButtonPress: if (*core->mouseCbk) { (*core->mouseCbk)(core->mouseCbkData, data->event); } break; case ButtonRelease: if (*core->mouseCbk) { (*core->mouseCbk)(core->mouseCbkData, data->event); } break; case MotionNotify: if (core->doc && core->doc->getNumPages() > 0) { ok = core->cvtWindowToDev(data->event->xmotion.x, data->event->xmotion.y, &pg, &x, &y); if (core->dragging) { if (ok) { core->moveSelection(pg, x, y); } } else if (core->hyperlinksEnabled) { core->cvtDevToUser(pg, x, y, &xu, &yu); if (ok && (action = core->findLink(pg, xu, yu))) { core->setCursor(core->linkCursor); if (action != core->linkAction) { core->linkAction = action; if (core->updateCbk) { s = ""; switch (action->getKind()) { case actionGoTo: s = "[internal link]"; break; case actionGoToR: s = ((LinkGoToR *)action)->getFileName()->getCString(); break; case actionLaunch: s = ((LinkLaunch *)action)->getFileName()->getCString(); break; case actionURI: s = ((LinkURI *)action)->getURI()->getCString(); break; case actionNamed: s = ((LinkNamed *)action)->getName()->getCString(); break; case actionMovie: s = "[movie]"; break; case actionUnknown: s = "[unknown link]"; break; } (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, s); } } } else { core->setCursor(None); if (core->linkAction) { core->linkAction = NULL; if (core->updateCbk) { (*core->updateCbk)(core->updateCbkData, NULL, -1, -1, ""); } } } } } if (core->panning) { core->scrollTo(core->scrollX - (data->event->xmotion.x - core->panMX), core->scrollY - (data->event->xmotion.y - core->panMY)); core->panMX = data->event->xmotion.x; core->panMY = data->event->xmotion.y; } break; case KeyPress: if (core->keyPressCbk) { key = XLookupKeysym(&data->event->xkey, (data->event->xkey.state & ShiftMask) ? 1 : 0); (*core->keyPressCbk)(core->keyPressCbkData, key, data->event->xkey.state, data->event); } break; } } PDFCoreTile *XPDFCore::newTile(int xDestA, int yDestA) { return new XPDFCoreTile(xDestA, yDestA); } void XPDFCore::updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc, int width, int height, GBool composited) { XPDFCoreTile *tile = (XPDFCoreTile *)tileA; XImage *image; SplashColorPtr dataPtr, p; Gulong pixel; Guchar *ap; Guchar alpha, alpha1; int w, h, bw, x, y, r, g, b, gray; int *errDownR, *errDownG, *errDownB; int errRightR, errRightG, errRightB; int errDownRightR, errDownRightG, errDownRightB; int r0, g0, b0, re, ge, be; if (!tile->image) { w = tile->xMax - tile->xMin; h = tile->yMax - tile->yMin; image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, w, h, 8, 0); image->data = (char *)gmallocn(h, image->bytes_per_line); tile->image = image; } else { image = (XImage *)tile->image; } //~ optimize for known XImage formats bw = tile->bitmap->getRowSize(); dataPtr = tile->bitmap->getDataPtr(); if (trueColor) { for (y = 0; y < height; ++y) { p = dataPtr + (ySrc + y) * bw + xSrc * 3; if (!composited && tile->bitmap->getAlphaPtr()) { ap = tile->bitmap->getAlphaPtr() + (ySrc + y) * tile->bitmap->getWidth() + xSrc; } else { ap = NULL; } for (x = 0; x < width; ++x) { r = splashRGB8R(p); g = splashRGB8G(p); b = splashRGB8B(p); if (ap) { alpha = *ap++; alpha1 = 255 - alpha; r = div255(alpha1 * paperColor[0] + alpha * r); g = div255(alpha1 * paperColor[1] + alpha * g); b = div255(alpha1 * paperColor[2] + alpha * b); } r >>= rDiv; g >>= gDiv; b >>= bDiv; pixel = ((Gulong)r << rShift) + ((Gulong)g << gShift) + ((Gulong)b << bShift); XPutPixel(image, xSrc + x, ySrc + y, pixel); p += 3; } } } else if (rgbCubeSize == 1) { //~ this should really use splashModeMono, with non-clustered dithering for (y = 0; y < height; ++y) { p = dataPtr + (ySrc + y) * bw + xSrc * 3; if (!composited && tile->bitmap->getAlphaPtr()) { ap = tile->bitmap->getAlphaPtr() + (ySrc + y) * tile->bitmap->getWidth() + xSrc; } else { ap = NULL; } for (x = 0; x < width; ++x) { r = splashRGB8R(p); g = splashRGB8G(p); b = splashRGB8B(p); if (ap) { alpha = *ap++; alpha1 = 255 - alpha; r = div255(alpha1 * paperColor[0] + alpha * r); g = div255(alpha1 * paperColor[1] + alpha * g); b = div255(alpha1 * paperColor[2] + alpha * b); } gray = (int)(0.299 * r + 0.587 * g + 0.114 * b + 0.5); if (gray < 128) { pixel = colors[0]; } else { pixel = colors[1]; } XPutPixel(image, xSrc + x, ySrc + y, pixel); p += 3; } } } else { // do Floyd-Steinberg dithering on the whole bitmap errDownR = (int *)gmallocn(width + 2, sizeof(int)); errDownG = (int *)gmallocn(width + 2, sizeof(int)); errDownB = (int *)gmallocn(width + 2, sizeof(int)); errRightR = errRightG = errRightB = 0; errDownRightR = errDownRightG = errDownRightB = 0; memset(errDownR, 0, (width + 2) * sizeof(int)); memset(errDownG, 0, (width + 2) * sizeof(int)); memset(errDownB, 0, (width + 2) * sizeof(int)); for (y = 0; y < height; ++y) { p = dataPtr + (ySrc + y) * bw + xSrc * 3; if (!composited && tile->bitmap->getAlphaPtr()) { ap = tile->bitmap->getAlphaPtr() + (ySrc + y) * tile->bitmap->getWidth() + xSrc; } else { ap = NULL; } for (x = 0; x < width; ++x) { r = splashRGB8R(p); g = splashRGB8G(p); b = splashRGB8B(p); if (ap) { alpha = *ap++; alpha1 = 255 - alpha; r = div255(alpha1 * paperColor[0] + alpha * r); g = div255(alpha1 * paperColor[1] + alpha * g); b = div255(alpha1 * paperColor[2] + alpha * b); } r0 = r + errRightR + errDownR[x+1]; g0 = g + errRightG + errDownG[x+1]; b0 = b + errRightB + errDownB[x+1]; if (r0 < 0) { r = 0; } else if (r0 >= 255) { r = rgbCubeSize - 1; } else { r = div255(r0 * (rgbCubeSize - 1)); } if (g0 < 0) { g = 0; } else if (g0 >= 255) { g = rgbCubeSize - 1; } else { g = div255(g0 * (rgbCubeSize - 1)); } if (b0 < 0) { b = 0; } else if (b0 >= 255) { b = rgbCubeSize - 1; } else { b = div255(b0 * (rgbCubeSize - 1)); } re = r0 - ((r << 8) - r) / (rgbCubeSize - 1); ge = g0 - ((g << 8) - g) / (rgbCubeSize - 1); be = b0 - ((b << 8) - b) / (rgbCubeSize - 1); errRightR = (re * 7) >> 4; errRightG = (ge * 7) >> 4; errRightB = (be * 7) >> 4; errDownR[x] += (re * 3) >> 4; errDownG[x] += (ge * 3) >> 4; errDownB[x] += (be * 3) >> 4; errDownR[x+1] = ((re * 5) >> 4) + errDownRightR; errDownG[x+1] = ((ge * 5) >> 4) + errDownRightG; errDownB[x+1] = ((be * 5) >> 4) + errDownRightB; errDownRightR = re >> 4; errDownRightG = ge >> 4; errDownRightB = be >> 4; pixel = colors[(r * rgbCubeSize + g) * rgbCubeSize + b]; XPutPixel(image, xSrc + x, ySrc + y, pixel); p += 3; } } gfree(errDownR); gfree(errDownG); gfree(errDownB); } } void XPDFCore::redrawRect(PDFCoreTile *tileA, int xSrc, int ySrc, int xDest, int yDest, int width, int height, GBool composited) { XPDFCoreTile *tile = (XPDFCoreTile *)tileA; Window drawAreaWin; XGCValues gcValues; // create a GC for the drawing area drawAreaWin = XtWindow(drawArea); if (!drawAreaGC) { gcValues.foreground = mattePixel; drawAreaGC = XCreateGC(display, drawAreaWin, GCForeground, &gcValues); } // draw the document if (tile) { XPutImage(display, drawAreaWin, drawAreaGC, tile->image, xSrc, ySrc, xDest, yDest, width, height); // draw the background } else { XFillRectangle(display, drawAreaWin, drawAreaGC, xDest, yDest, width, height); } } void XPDFCore::updateScrollbars() { Arg args[20]; int n; int maxPos; if (pages->getLength() > 0) { if (continuousMode) { maxPos = maxPageW; } else { maxPos = ((PDFCorePage *)pages->get(0))->w; } } else { maxPos = 1; } if (maxPos < drawAreaWidth) { maxPos = drawAreaWidth; } n = 0; XtSetArg(args[n], XmNvalue, scrollX); ++n; XtSetArg(args[n], XmNmaximum, maxPos); ++n; XtSetArg(args[n], XmNsliderSize, drawAreaWidth); ++n; XtSetArg(args[n], XmNincrement, 16); ++n; XtSetArg(args[n], XmNpageIncrement, drawAreaWidth); ++n; XtSetValues(hScrollBar, args, n); if (pages->getLength() > 0) { if (continuousMode) { maxPos = totalDocH; } else { maxPos = ((PDFCorePage *)pages->get(0))->h; } } else { maxPos = 1; } if (maxPos < drawAreaHeight) { maxPos = drawAreaHeight; } n = 0; XtSetArg(args[n], XmNvalue, scrollY); ++n; XtSetArg(args[n], XmNmaximum, maxPos); ++n; XtSetArg(args[n], XmNsliderSize, drawAreaHeight); ++n; XtSetArg(args[n], XmNincrement, 16); ++n; XtSetArg(args[n], XmNpageIncrement, drawAreaHeight); ++n; XtSetValues(vScrollBar, args, n); } void XPDFCore::setCursor(Cursor cursor) { Window topWin; if (cursor == currentCursor) { return; } if (!(topWin = XtWindow(shell))) { return; } if (cursor == None) { XUndefineCursor(display, topWin); } else { XDefineCursor(display, topWin, cursor); } XFlush(display); currentCursor = cursor; } GBool XPDFCore::doQuestionDialog(const char *title, GString *msg) { return doDialog(XmDIALOG_QUESTION, gTrue, title, msg); } void XPDFCore::doInfoDialog(const char *title, GString *msg) { doDialog(XmDIALOG_INFORMATION, gFalse, title, msg); } void XPDFCore::doErrorDialog(const char *title, GString *msg) { doDialog(XmDIALOG_ERROR, gFalse, title, msg); } GBool XPDFCore::doDialog(int type, GBool hasCancel, const char *title, GString *msg) { Widget dialog, scroll, text; XtAppContext appContext; Arg args[20]; int n; XmString s1, s2; XEvent event; n = 0; XtSetArg(args[n], XmNdialogType, type); ++n; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; s1 = XmStringCreateLocalized((char *)title); XtSetArg(args[n], XmNdialogTitle, s1); ++n; s2 = NULL; // make gcc happy if (msg->getLength() <= 80) { s2 = XmStringCreateLocalized(msg->getCString()); XtSetArg(args[n], XmNmessageString, s2); ++n; } dialog = XmCreateMessageDialog(drawArea, "questionDialog", args, n); XmStringFree(s1); if (msg->getLength() <= 80) { XmStringFree(s2); } else { n = 0; XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n; if (drawAreaWidth > 300) { XtSetArg(args[n], XmNwidth, drawAreaWidth - 100); ++n; } scroll = XmCreateScrolledWindow(dialog, "scroll", args, n); XtManageChild(scroll); n = 0; XtSetArg(args[n], XmNeditable, False); ++n; XtSetArg(args[n], XmNeditMode, XmMULTI_LINE_EDIT); ++n; XtSetArg(args[n], XmNvalue, msg->getCString()); ++n; XtSetArg(args[n], XmNshadowThickness, 0); ++n; text = XmCreateText(scroll, "text", args, n); XtManageChild(text); } XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON)); XtAddCallback(dialog, XmNokCallback, &dialogOkCbk, (XtPointer)this); if (hasCancel) { XtAddCallback(dialog, XmNcancelCallback, &dialogCancelCbk, (XtPointer)this); } else { XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON)); } XtManageChild(dialog); appContext = XtWidgetToApplicationContext(dialog); dialogDone = 0; do { XtAppNextEvent(appContext, &event); XtDispatchEvent(&event); } while (!dialogDone); XtUnmanageChild(dialog); XtDestroyWidget(dialog); return dialogDone > 0; } void XPDFCore::dialogOkCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; core->dialogDone = 1; } void XPDFCore::dialogCancelCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; core->dialogDone = -1; } //------------------------------------------------------------------------ // password dialog //------------------------------------------------------------------------ void XPDFCore::initPasswordDialog() { Widget row, label, okBtn, cancelBtn; Arg args[20]; int n; XmString s; //----- dialog n = 0; s = XmStringCreateLocalized(xpdfAppName ": Password"); XtSetArg(args[n], XmNdialogTitle, s); ++n; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; passwordDialog = XmCreateFormDialog(drawArea, "passwordDialog", args, n); XmStringFree(s); //----- message n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNtopOffset, 4); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; s = XmStringCreateLocalized("This document requires a password."); XtSetArg(args[n], XmNlabelString, s); ++n; label = XmCreateLabel(passwordDialog, "msg", args, n); XmStringFree(s); XtManageChild(label); //----- label and password entry n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, label); ++n; XtSetArg(args[n], XmNtopOffset, 4); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n; row = XmCreateRowColumn(passwordDialog, "row", args, n); XtManageChild(row); n = 0; s = XmStringCreateLocalized("Password: "); XtSetArg(args[n], XmNlabelString, s); ++n; label = XmCreateLabel(row, "label", args, n); XmStringFree(s); XtManageChild(label); n = 0; XtSetArg(args[n], XmNcolumns, 16); ++n; passwordText = XmCreateTextField(row, "text", args, n); XtManageChild(passwordText); XtAddCallback(passwordText, XmNmodifyVerifyCallback, &passwordTextVerifyCbk, this); //----- "Ok" and "Cancel" buttons n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, row); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n; okBtn = XmCreatePushButton(passwordDialog, "Ok", args, n); XtManageChild(okBtn); XtAddCallback(okBtn, XmNactivateCallback, &passwordOkCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, row); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n; cancelBtn = XmCreatePushButton(passwordDialog, "Cancel", args, n); XtManageChild(cancelBtn); XtAddCallback(cancelBtn, XmNactivateCallback, &passwordCancelCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNdefaultButton, okBtn); ++n; XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n; #if XmVersion > 1001 XtSetArg(args[n], XmNinitialFocus, passwordText); ++n; #endif XtSetValues(passwordDialog, args, n); } void XPDFCore::passwordTextVerifyCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; XmTextVerifyCallbackStruct *data = (XmTextVerifyCallbackStruct *)callData; int i, n; i = (int)data->startPos; n = (int)data->endPos - i; if (i > core->password->getLength()) { i = core->password->getLength(); } if (i + n > core->password->getLength()) { n = core->password->getLength() - i; } core->password->del(i, n); core->password->insert(i, data->text->ptr, data->text->length); for (i = 0; i < data->text->length; ++i) { data->text->ptr[i] = '*'; } data->doit = True; } void XPDFCore::passwordOkCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; core->dialogDone = 1; } void XPDFCore::passwordCancelCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFCore *core = (XPDFCore *)ptr; core->dialogDone = -1; } GString *XPDFCore::getPassword() { XtAppContext appContext; XEvent event; // NB: set before calling XmTextFieldSetString, because // SetString will trigger a call to passwordTextVerifyCbk, which // expects to be valid password = new GString(); XmTextFieldSetString(passwordText, ""); XtManageChild(passwordDialog); appContext = XtWidgetToApplicationContext(passwordDialog); dialogDone = 0; do { XtAppNextEvent(appContext, &event); XtDispatchEvent(&event); } while (!dialogDone); XtUnmanageChild(passwordDialog); if (dialogDone < 0) { delete password; return NULL; } return password; } xpdf-3.03/xpdf/xpdfIcon.xpm0000644000076400007640000000527711622305345015167 0ustar dereknderekn/* XPM */ static char *xpdfIcon[] = { /* width height num_colors chars_per_pixel */ " 48 48 7 1", /* colors */ ". c #000000", "# c #a00000", "a c #a0a0a0", "b c #c0c0c0", "c c #e00000", "d c #e0e0e0", "e c #ffffff", /* pixels */ "................................................", "................................................", "................................................", "................................................", "#ccccccc#................................#ccc#..", ".#ccccccc#..............................#ccc#...", "..#ccccccc#............................#ccc#....", "...#ccccccc#................bbba.....abbbc#.....", "....#ccccccc#...............beea....debbed......", ".....#ccccccc#...............ee....bebccee......", "......#ccccccc#..............ee....eecc#bb......", ".......#ccccccc#............aee...#eec#.........", "........#ccccccc#...........bed..#beb#..........", ".........#ccccccc#..........beb.#cbeb...........", "..........#ccccccc#.........beb#ccbeb...........", "...........#ccccccc#........bebcccbeb...........", "............#ccccccc#.......eebcc#dea...........", ".............#ccccccc#......eecc#.ee............", ".........ae...#ccccccc#....#eec#..ee............", "........aeeaeeeebcccccabeeeaee#.beeeeee.........", ".......aeeeea..debcccaed##ceee....ee............", "......addee.....eeccaedccccbed...beb............", "......a.bee.....ee#cbeaccccbeb...beb............", "........beb.....ee.#eecccccbeb...beb............", "........beb.....ee..eecccccbeb...beb............", "........beb.....ee..eeccccceeb...dea............", "........deb....aeb.#eeccccceec#..ee.............", "........eea....dea#cee##ccceecc#.ee.............", "........eee...dea#ccbeda#cdeeccc#ee.............", "........eeaeeeba#ccc#beeeeaeeecceeee............", "........ee.....#ccc#......#ccccccc#.............", ".......bee....#ccc#........#ccccccc#............", ".......beb...#ccc#..........#ccccccc#...........", ".......beb..#ccc#............#ccccccc#..........", ".......beb.#ccc#..............#ccccccc#.........", ".......deb#ccc#................#ccccccc#........", ".......eeaccc#..................#ccccccc#.......", ".......eeccc#....................#ccccccc#......", ".......eecc#......................#ccccccc#.....", "......beeb#........................#ccccccc#....", ".....#bbbb..........................#ccccccc#...", "....#ccc#............................#ccccccc#..", "...#ccc#..............................#ccccccc#.", "..#ccc#................................#ccccccc.", "................................................", "................................................", "................................................", "................................................" }; xpdf-3.03/xpdf/Stream.h0000644000076400007640000006452411622305345014273 0ustar dereknderekn//======================================================================== // // Stream.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef STREAM_H #define STREAM_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "gtypes.h" #include "Object.h" class BaseStream; //------------------------------------------------------------------------ enum StreamKind { strFile, strASCIIHex, strASCII85, strLZW, strRunLength, strCCITTFax, strDCT, strFlate, strJBIG2, strJPX, strWeird // internal-use stream types }; enum StreamColorSpaceMode { streamCSNone, streamCSDeviceGray, streamCSDeviceRGB, streamCSDeviceCMYK }; //------------------------------------------------------------------------ // This is in Stream.h instead of Decrypt.h to avoid really annoying // include file dependency loops. enum CryptAlgorithm { cryptRC4, cryptAES, cryptAES256 }; //------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ class Stream { public: // Constructor. Stream(); // Destructor. virtual ~Stream(); // Reference counting. int incRef() { return ++ref; } int decRef() { return --ref; } // Get kind of stream. virtual StreamKind getKind() = 0; // Reset stream to beginning. virtual void reset() = 0; // Close down the stream. virtual void close(); // Get next char from stream. virtual int getChar() = 0; // Peek at next char in stream. virtual int lookChar() = 0; // Get next char from stream without using the predictor. // This is only used by StreamPredictor. virtual int getRawChar(); // Get exactly bytes from stream. Returns the number of // bytes read -- the returned count will be less than at EOF. virtual int getBlock(char *blk, int size); // Get next line from stream. virtual char *getLine(char *buf, int size); // Get current position in file. virtual int getPos() = 0; // Go to a position in the stream. If
is negative, the // position is from the end of the file; otherwise the position is // from the start of the file. virtual void setPos(Guint pos, int dir = 0) = 0; // Get PostScript command for the filter(s). virtual GString *getPSFilter(int psLevel, const char *indent); // Does this stream type potentially contain non-printable chars? virtual GBool isBinary(GBool last = gTrue) = 0; // Get the BaseStream of this stream. virtual BaseStream *getBaseStream() = 0; // Get the stream after the last decoder (this may be a BaseStream // or a DecryptStream). virtual Stream *getUndecodedStream() = 0; // Get the dictionary associated with this stream. virtual Dict *getDict() = 0; // Is this an encoding filter? virtual GBool isEncoder() { return gFalse; } // Get image parameters which are defined by the stream contents. virtual void getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode) {} // Return the next stream in the "stack". virtual Stream *getNextStream() { return NULL; } // Add filters to this stream according to the parameters in . // Returns the new stream. Stream *addFilters(Object *dict); private: Stream *makeFilter(char *name, Stream *str, Object *params); int ref; // reference count }; //------------------------------------------------------------------------ // BaseStream // // This is the base class for all streams that read directly from a file. //------------------------------------------------------------------------ class BaseStream: public Stream { public: BaseStream(Object *dictA); virtual ~BaseStream(); virtual Stream *makeSubStream(Guint start, GBool limited, Guint length, Object *dict) = 0; virtual void setPos(Guint pos, int dir = 0) = 0; virtual GBool isBinary(GBool last = gTrue) { return last; } virtual BaseStream *getBaseStream() { return this; } virtual Stream *getUndecodedStream() { return this; } virtual Dict *getDict() { return dict.getDict(); } virtual GString *getFileName() { return NULL; } // Get/set position of first byte of stream within the file. virtual Guint getStart() = 0; virtual void moveStart(int delta) = 0; private: Object dict; }; //------------------------------------------------------------------------ // FilterStream // // This is the base class for all streams that filter another stream. //------------------------------------------------------------------------ class FilterStream: public Stream { public: FilterStream(Stream *strA); virtual ~FilterStream(); virtual void close(); virtual int getPos() { return str->getPos(); } virtual void setPos(Guint pos, int dir = 0); virtual BaseStream *getBaseStream() { return str->getBaseStream(); } virtual Stream *getUndecodedStream() { return str->getUndecodedStream(); } virtual Dict *getDict() { return str->getDict(); } virtual Stream *getNextStream() { return str; } protected: Stream *str; }; //------------------------------------------------------------------------ // ImageStream //------------------------------------------------------------------------ class ImageStream { public: // Create an image stream object for an image with the specified // parameters. Note that these are the actual image parameters, // which may be different from the predictor parameters. ImageStream(Stream *strA, int widthA, int nCompsA, int nBitsA); ~ImageStream(); // Reset the stream. void reset(); // Gets the next pixel from the stream. should be able to hold // at least nComps elements. Returns false at end of file. GBool getPixel(Guchar *pix); // Returns a pointer to the next line of pixels. Returns NULL at // end of file. Guchar *getLine(); // Skip an entire line from the image. void skipLine(); private: Stream *str; // base stream int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line int inputLineSize; // input line buffer size char *inputLine; // input line buffer Guchar *imgLine; // line buffer int imgIdx; // current index in imgLine }; //------------------------------------------------------------------------ // StreamPredictor //------------------------------------------------------------------------ class StreamPredictor { public: // Create a predictor object. Note that the parameters are for the // predictor, and may not match the actual image parameters. StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA); ~StreamPredictor(); GBool isOk() { return ok; } int lookChar(); int getChar(); int getBlock(char *blk, int size); private: GBool getNextLine(); Stream *str; // base stream int predictor; // predictor int width; // pixels per line int nComps; // components per pixel int nBits; // bits per component int nVals; // components per line int pixBytes; // bytes per pixel int rowBytes; // bytes per line Guchar *predLine; // line buffer int predIdx; // current index in predLine GBool ok; }; //------------------------------------------------------------------------ // FileStream //------------------------------------------------------------------------ #define fileStreamBufSize 256 class FileStream: public BaseStream { public: FileStream(FILE *fA, Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual ~FileStream(); virtual Stream *makeSubStream(Guint startA, GBool limitedA, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strFile; } virtual void reset(); virtual void close(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getBlock(char *blk, int size); virtual int getPos() { return bufPos + (int)(bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart() { return start; } virtual void moveStart(int delta); private: GBool fillBuf(); FILE *f; Guint start; GBool limited; Guint length; char buf[fileStreamBufSize]; char *bufPtr; char *bufEnd; Guint bufPos; int savePos; GBool saved; }; //------------------------------------------------------------------------ // MemStream //------------------------------------------------------------------------ class MemStream: public BaseStream { public: MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA); virtual ~MemStream(); virtual Stream *makeSubStream(Guint start, GBool limited, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual void close(); virtual int getChar() { return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; } virtual int lookChar() { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } virtual int getBlock(char *blk, int size); virtual int getPos() { return (int)(bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart() { return start; } virtual void moveStart(int delta); private: char *buf; Guint start; Guint length; char *bufEnd; char *bufPtr; GBool needFree; }; //------------------------------------------------------------------------ // EmbedStream // // This is a special stream type used for embedded streams (inline // images). It reads directly from the base stream -- after the // EmbedStream is deleted, reads from the base stream will proceed where // the BaseStream left off. Note that this is very different behavior // that creating a new FileStream (using makeSubStream). //------------------------------------------------------------------------ class EmbedStream: public BaseStream { public: EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); virtual ~EmbedStream(); virtual Stream *makeSubStream(Guint start, GBool limitedA, Guint lengthA, Object *dictA); virtual StreamKind getKind() { return str->getKind(); } virtual void reset() {} virtual int getChar(); virtual int lookChar(); virtual int getBlock(char *blk, int size); virtual int getPos() { return str->getPos(); } virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart(); virtual void moveStart(int delta); private: Stream *str; GBool limited; Guint length; }; //------------------------------------------------------------------------ // ASCIIHexStream //------------------------------------------------------------------------ class ASCIIHexStream: public FilterStream { public: ASCIIHexStream(Stream *strA); virtual ~ASCIIHexStream(); virtual StreamKind getKind() { return strASCIIHex; } virtual void reset(); virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: int buf; GBool eof; }; //------------------------------------------------------------------------ // ASCII85Stream //------------------------------------------------------------------------ class ASCII85Stream: public FilterStream { public: ASCII85Stream(Stream *strA); virtual ~ASCII85Stream(); virtual StreamKind getKind() { return strASCII85; } virtual void reset(); virtual int getChar() { int ch = lookChar(); ++index; return ch; } virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: int c[5]; int b[4]; int index, n; GBool eof; }; //------------------------------------------------------------------------ // LZWStream //------------------------------------------------------------------------ class LZWStream: public FilterStream { public: LZWStream(Stream *strA, int predictor, int columns, int colors, int bits, int earlyA); virtual ~LZWStream(); virtual StreamKind getKind() { return strLZW; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); virtual int getBlock(char *blk, int size); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: StreamPredictor *pred; // predictor int early; // early parameter GBool eof; // true if at eof int inputBuf; // input buffer int inputBits; // number of bits in input buffer struct { // decoding table int length; int head; Guchar tail; } table[4097]; int nextCode; // next code to be used int nextBits; // number of bits in next code word int prevCode; // previous code used in stream int newChar; // next char to be added to table Guchar seqBuf[4097]; // buffer for current sequence int seqLength; // length of current sequence int seqIndex; // index into current sequence GBool first; // first code after a table clear GBool processNextCode(); void clearTable(); int getCode(); }; //------------------------------------------------------------------------ // RunLengthStream //------------------------------------------------------------------------ class RunLengthStream: public FilterStream { public: RunLengthStream(Stream *strA); virtual ~RunLengthStream(); virtual StreamKind getKind() { return strRunLength; } virtual void reset(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getBlock(char *blk, int size); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: char buf[128]; // buffer char *bufPtr; // next char to read char *bufEnd; // end of buffer GBool eof; GBool fillBuf(); }; //------------------------------------------------------------------------ // CCITTFaxStream //------------------------------------------------------------------------ struct CCITTCodeTable; class CCITTFaxStream: public FilterStream { public: CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, GBool byteAlignA, int columnsA, int rowsA, GBool endOfBlockA, GBool blackA); virtual ~CCITTFaxStream(); virtual StreamKind getKind() { return strCCITTFax; } virtual void reset(); virtual int getChar() { int c = lookChar(); buf = EOF; return c; } virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: int encoding; // 'K' parameter GBool endOfLine; // 'EndOfLine' parameter GBool byteAlign; // 'EncodedByteAlign' parameter int columns; // 'Columns' parameter int rows; // 'Rows' parameter GBool endOfBlock; // 'EndOfBlock' parameter GBool black; // 'BlackIs1' parameter GBool eof; // true if at eof GBool nextLine2D; // true if next line uses 2D encoding int row; // current row Guint inputBuf; // input buffer int inputBits; // number of bits in input buffer int *codingLine; // coding line changing elements int *refLine; // reference line changing elements int a0i; // index into codingLine GBool err; // error on current line int outputBits; // remaining ouput bits int buf; // character buffer void addPixels(int a1, int blackPixels); void addPixelsNeg(int a1, int blackPixels); short getTwoDimCode(); short getWhiteCode(); short getBlackCode(); short lookBits(int n); void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; } }; //------------------------------------------------------------------------ // DCTStream //------------------------------------------------------------------------ // DCT component info struct DCTCompInfo { int id; // component ID int hSample, vSample; // horiz/vert sampling resolutions int quantTable; // quantization table number int prevDC; // DC coefficient accumulator }; struct DCTScanInfo { GBool comp[4]; // comp[i] is set if component i is // included in this scan int numComps; // number of components in the scan int dcHuffTable[4]; // DC Huffman table numbers int acHuffTable[4]; // AC Huffman table numbers int firstCoeff, lastCoeff; // first and last DCT coefficient int ah, al; // successive approximation parameters }; // DCT Huffman decoding table struct DCTHuffTable { Guchar firstSym[17]; // first symbol for this bit length Gushort firstCode[17]; // first code for this bit length Gushort numCodes[17]; // number of codes of this bit length Guchar sym[256]; // symbols }; class DCTStream: public FilterStream { public: DCTStream(Stream *strA, int colorXformA); virtual ~DCTStream(); virtual StreamKind getKind() { return strDCT; } virtual void reset(); virtual void close(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); Stream *getRawStream() { return str; } private: GBool progressive; // set if in progressive mode GBool interleaved; // set if in interleaved mode int width, height; // image size int mcuWidth, mcuHeight; // size of min coding unit, in data units int bufWidth, bufHeight; // frameBuf size DCTCompInfo compInfo[4]; // info for each component DCTScanInfo scanInfo; // info for the current scan int numComps; // number of components in image int colorXform; // color transform: -1 = unspecified // 0 = none // 1 = YUV/YUVK -> RGB/CMYK GBool gotJFIFMarker; // set if APP0 JFIF marker was present GBool gotAdobeMarker; // set if APP14 Adobe marker was present int restartInterval; // restart interval, in MCUs Gushort quantTables[4][64]; // quantization tables int numQuantTables; // number of quantization tables DCTHuffTable dcHuffTables[4]; // DC Huffman tables DCTHuffTable acHuffTables[4]; // AC Huffman tables int numDCHuffTables; // number of DC Huffman tables int numACHuffTables; // number of AC Huffman tables Guchar *rowBuf[4][32]; // buffer for one MCU (non-progressive mode) int *frameBuf[4]; // buffer for frame (progressive mode) int comp, x, y, dy; // current position within image/MCU int restartCtr; // MCUs left until restart int restartMarker; // next restart marker int eobRun; // number of EOBs left in the current run int inputBuf; // input buffer for variable length codes int inputBits; // number of valid bits in input buffer void restart(); GBool readMCURow(); void readScan(); GBool readDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]); GBool readProgressiveDataUnit(DCTHuffTable *dcHuffTable, DCTHuffTable *acHuffTable, int *prevDC, int data[64]); void decodeImage(); void transformDataUnit(Gushort *quantTable, int dataIn[64], Guchar dataOut[64]); int readHuffSym(DCTHuffTable *table); int readAmp(int size); int readBit(); GBool readHeader(); GBool readBaselineSOF(); GBool readProgressiveSOF(); GBool readScanInfo(); GBool readQuantTables(); GBool readHuffmanTables(); GBool readRestartInterval(); GBool readJFIFMarker(); GBool readAdobeMarker(); GBool readTrailer(); int readMarker(); int read16(); }; //------------------------------------------------------------------------ // FlateStream //------------------------------------------------------------------------ #define flateWindow 32768 // buffer size #define flateMask (flateWindow-1) #define flateMaxHuffman 15 // max Huffman code length #define flateMaxCodeLenCodes 19 // max # code length codes #define flateMaxLitCodes 288 // max # literal codes #define flateMaxDistCodes 30 // max # distance codes // Huffman code table entry struct FlateCode { Gushort len; // code length, in bits Gushort val; // value represented by this code }; struct FlateHuffmanTab { FlateCode *codes; int maxLen; }; // Decoding info for length and distance code words struct FlateDecode { int bits; // # extra bits int first; // first length/distance }; class FlateStream: public FilterStream { public: FlateStream(Stream *strA, int predictor, int columns, int colors, int bits); virtual ~FlateStream(); virtual StreamKind getKind() { return strFlate; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual int getRawChar(); virtual int getBlock(char *blk, int size); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); private: StreamPredictor *pred; // predictor Guchar buf[flateWindow]; // output data buffer int index; // current index into output buffer int remain; // number valid bytes in output buffer int codeBuf; // input buffer int codeSize; // number of bits in input buffer int // literal and distance code lengths codeLengths[flateMaxLitCodes + flateMaxDistCodes]; FlateHuffmanTab litCodeTab; // literal code table FlateHuffmanTab distCodeTab; // distance code table GBool compressedBlock; // set if reading a compressed block int blockLen; // remaining length of uncompressed block GBool endOfBlock; // set when end of block is reached GBool eof; // set when end of stream is reached static int // code length code reordering codeLenCodeMap[flateMaxCodeLenCodes]; static FlateDecode // length decoding info lengthDecode[flateMaxLitCodes-257]; static FlateDecode // distance decoding info distDecode[flateMaxDistCodes]; static FlateHuffmanTab // fixed literal code table fixedLitCodeTab; static FlateHuffmanTab // fixed distance code table fixedDistCodeTab; void readSome(); GBool startBlock(); void loadFixedCodes(); GBool readDynamicCodes(); void compHuffmanCodes(int *lengths, int n, FlateHuffmanTab *tab); int getHuffmanCodeWord(FlateHuffmanTab *tab); int getCodeWord(int bits); }; //------------------------------------------------------------------------ // EOFStream //------------------------------------------------------------------------ class EOFStream: public FilterStream { public: EOFStream(Stream *strA); virtual ~EOFStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset() {} virtual int getChar() { return EOF; } virtual int lookChar() { return EOF; } virtual int getBlock(char *blk, int size) { return 0; } virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } }; //------------------------------------------------------------------------ // BufStream //------------------------------------------------------------------------ class BufStream: public FilterStream { public: BufStream(Stream *strA, int bufSizeA); virtual ~BufStream(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue); int lookChar(int idx); private: int *buf; int bufSize; }; //------------------------------------------------------------------------ // FixedLengthEncoder //------------------------------------------------------------------------ class FixedLengthEncoder: public FilterStream { public: FixedLengthEncoder(Stream *strA, int lengthA); ~FixedLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue); virtual GBool isEncoder() { return gTrue; } private: int length; int count; }; //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ class ASCIIHexEncoder: public FilterStream { public: ASCIIHexEncoder(Stream *strA); virtual ~ASCIIHexEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } private: char buf[4]; char *bufPtr; char *bufEnd; int lineLen; GBool eof; GBool fillBuf(); }; //------------------------------------------------------------------------ // ASCII85Encoder //------------------------------------------------------------------------ class ASCII85Encoder: public FilterStream { public: ASCII85Encoder(Stream *strA); virtual ~ASCII85Encoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gFalse; } virtual GBool isEncoder() { return gTrue; } private: char buf[8]; char *bufPtr; char *bufEnd; int lineLen; GBool eof; GBool fillBuf(); }; //------------------------------------------------------------------------ // RunLengthEncoder //------------------------------------------------------------------------ class RunLengthEncoder: public FilterStream { public: RunLengthEncoder(Stream *strA); virtual ~RunLengthEncoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual GString *getPSFilter(int psLevel, const char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } private: char buf[131]; char *bufPtr; char *bufEnd; char *nextEnd; GBool eof; GBool fillBuf(); }; #endif xpdf-3.03/xpdf/ImageOutputDev.h0000644000076400007640000000517011622305345015732 0ustar dereknderekn//======================================================================== // // ImageOutputDev.h // // Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== #ifndef IMAGEOUTPUTDEV_H #define IMAGEOUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "gtypes.h" #include "OutputDev.h" class GfxState; //------------------------------------------------------------------------ // ImageOutputDev //------------------------------------------------------------------------ class ImageOutputDev: public OutputDev { public: // Create an OutputDev which will write images to files named // -NNN.. Normally, all images are written as PBM // (.pbm) or PPM (.ppm) files. If is set, JPEG images are // written as JPEG (.jpg) files. ImageOutputDev(char *fileRootA, GBool dumpJPEGA); // Destructor. virtual ~ImageOutputDev(); // Check if file was successfully created. virtual GBool isOk() { return ok; } // Does this device use tilingPatternFill()? If this returns false, // tiling pattern fills will be reduced to a series of other drawing // operations. virtual GBool useTilingPatternFill() { return gTrue; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } // Does this device need non-text content? virtual GBool needNonText() { return gTrue; } //---- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gTrue; } // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gFalse; } //----- path painting virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep); //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); private: char *fileRoot; // root of output file names char *fileName; // buffer for output file names GBool dumpJPEG; // set to dump native JPEG files int imgNum; // current image number GBool ok; // set up ok? }; #endif xpdf-3.03/xpdf/GfxState.h0000644000076400007640000011460311622305345014557 0ustar dereknderekn//======================================================================== // // GfxState.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFXSTATE_H #define GFXSTATE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" #include "Function.h" class Array; class GfxFont; class PDFRectangle; class GfxShading; //------------------------------------------------------------------------ // GfxBlendMode //------------------------------------------------------------------------ enum GfxBlendMode { gfxBlendNormal, gfxBlendMultiply, gfxBlendScreen, gfxBlendOverlay, gfxBlendDarken, gfxBlendLighten, gfxBlendColorDodge, gfxBlendColorBurn, gfxBlendHardLight, gfxBlendSoftLight, gfxBlendDifference, gfxBlendExclusion, gfxBlendHue, gfxBlendSaturation, gfxBlendColor, gfxBlendLuminosity }; //------------------------------------------------------------------------ // GfxColorComp //------------------------------------------------------------------------ // 16.16 fixed point color component typedef int GfxColorComp; #define gfxColorComp1 0x10000 static inline GfxColorComp dblToCol(double x) { return (GfxColorComp)(x * gfxColorComp1); } static inline double colToDbl(GfxColorComp x) { return (double)x / (double)gfxColorComp1; } static inline GfxColorComp byteToCol(Guchar x) { // (x / 255) << 16 = (0.0000000100000001... * x) << 16 // = ((x << 8) + (x) + (x >> 8) + ...) << 16 // = (x << 8) + (x) + (x >> 7) // [for rounding] return (GfxColorComp)((x << 8) + x + (x >> 7)); } static inline Guchar colToByte(GfxColorComp x) { // 255 * x + 0.5 = 256 * x - x + 0x8000 return (Guchar)(((x << 8) - x + 0x8000) >> 16); } //------------------------------------------------------------------------ // GfxColor //------------------------------------------------------------------------ #define gfxColorMaxComps funcMaxOutputs struct GfxColor { GfxColorComp c[gfxColorMaxComps]; }; //------------------------------------------------------------------------ // GfxGray //------------------------------------------------------------------------ typedef GfxColorComp GfxGray; //------------------------------------------------------------------------ // GfxRGB //------------------------------------------------------------------------ struct GfxRGB { GfxColorComp r, g, b; }; //------------------------------------------------------------------------ // GfxCMYK //------------------------------------------------------------------------ struct GfxCMYK { GfxColorComp c, m, y, k; }; //------------------------------------------------------------------------ // GfxColorSpace //------------------------------------------------------------------------ // NB: The nGfxColorSpaceModes constant and the gfxColorSpaceModeNames // array defined in GfxState.cc must match this enum. enum GfxColorSpaceMode { csDeviceGray, csCalGray, csDeviceRGB, csCalRGB, csDeviceCMYK, csLab, csICCBased, csIndexed, csSeparation, csDeviceN, csPattern }; class GfxColorSpace { public: GfxColorSpace(); virtual ~GfxColorSpace(); virtual GfxColorSpace *copy() = 0; virtual GfxColorSpaceMode getMode() = 0; // Construct a color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Object *csObj, int recursion = 0); // Convert to gray, RGB, or CMYK. virtual void getGray(GfxColor *color, GfxGray *gray) = 0; virtual void getRGB(GfxColor *color, GfxRGB *rgb) = 0; virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk) = 0; // Return the number of color components. virtual int getNComps() = 0; // Get this color space's default color. virtual void getDefaultColor(GfxColor *color) = 0; // Return the default ranges for each component, assuming an image // with a max pixel value of . virtual void getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel); // Returns true if painting operations in this color space never // mark the page (e.g., the "None" colorant). virtual GBool isNonMarking() { return gFalse; } // Return the color space's overprint mask. Guint getOverprintMask() { return overprintMask; } // Return the number of color space modes static int getNumColorSpaceModes(); // Return the name of the th color space mode. static const char *getColorSpaceModeName(int idx); protected: Guint overprintMask; }; //------------------------------------------------------------------------ // GfxDeviceGrayColorSpace //------------------------------------------------------------------------ class GfxDeviceGrayColorSpace: public GfxColorSpace { public: GfxDeviceGrayColorSpace(); virtual ~GfxDeviceGrayColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceGray; } virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); private: }; //------------------------------------------------------------------------ // GfxCalGrayColorSpace //------------------------------------------------------------------------ class GfxCalGrayColorSpace: public GfxColorSpace { public: GfxCalGrayColorSpace(); virtual ~GfxCalGrayColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csCalGray; } // Construct a CalGray color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); // CalGray-specific access. double getWhiteX() { return whiteX; } double getWhiteY() { return whiteY; } double getWhiteZ() { return whiteZ; } double getBlackX() { return blackX; } double getBlackY() { return blackY; } double getBlackZ() { return blackZ; } double getGamma() { return gamma; } private: double whiteX, whiteY, whiteZ; // white point double blackX, blackY, blackZ; // black point double gamma; // gamma value }; //------------------------------------------------------------------------ // GfxDeviceRGBColorSpace //------------------------------------------------------------------------ class GfxDeviceRGBColorSpace: public GfxColorSpace { public: GfxDeviceRGBColorSpace(); virtual ~GfxDeviceRGBColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceRGB; } virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 3; } virtual void getDefaultColor(GfxColor *color); private: }; //------------------------------------------------------------------------ // GfxCalRGBColorSpace //------------------------------------------------------------------------ class GfxCalRGBColorSpace: public GfxColorSpace { public: GfxCalRGBColorSpace(); virtual ~GfxCalRGBColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csCalRGB; } // Construct a CalRGB color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 3; } virtual void getDefaultColor(GfxColor *color); // CalRGB-specific access. double getWhiteX() { return whiteX; } double getWhiteY() { return whiteY; } double getWhiteZ() { return whiteZ; } double getBlackX() { return blackX; } double getBlackY() { return blackY; } double getBlackZ() { return blackZ; } double getGammaR() { return gammaR; } double getGammaG() { return gammaG; } double getGammaB() { return gammaB; } double *getMatrix() { return mat; } private: double whiteX, whiteY, whiteZ; // white point double blackX, blackY, blackZ; // black point double gammaR, gammaG, gammaB; // gamma values double mat[9]; // ABC -> XYZ transform matrix }; //------------------------------------------------------------------------ // GfxDeviceCMYKColorSpace //------------------------------------------------------------------------ class GfxDeviceCMYKColorSpace: public GfxColorSpace { public: GfxDeviceCMYKColorSpace(); virtual ~GfxDeviceCMYKColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceCMYK; } virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 4; } virtual void getDefaultColor(GfxColor *color); private: }; //------------------------------------------------------------------------ // GfxLabColorSpace //------------------------------------------------------------------------ class GfxLabColorSpace: public GfxColorSpace { public: GfxLabColorSpace(); virtual ~GfxLabColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csLab; } // Construct a Lab color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 3; } virtual void getDefaultColor(GfxColor *color); virtual void getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel); // Lab-specific access. double getWhiteX() { return whiteX; } double getWhiteY() { return whiteY; } double getWhiteZ() { return whiteZ; } double getBlackX() { return blackX; } double getBlackY() { return blackY; } double getBlackZ() { return blackZ; } double getAMin() { return aMin; } double getAMax() { return aMax; } double getBMin() { return bMin; } double getBMax() { return bMax; } private: double whiteX, whiteY, whiteZ; // white point double blackX, blackY, blackZ; // black point double aMin, aMax, bMin, bMax; // range for the a and b components double kr, kg, kb; // gamut mapping mulitpliers }; //------------------------------------------------------------------------ // GfxICCBasedColorSpace //------------------------------------------------------------------------ class GfxICCBasedColorSpace: public GfxColorSpace { public: GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA, Ref *iccProfileStreamA); virtual ~GfxICCBasedColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csICCBased; } // Construct an ICCBased color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return nComps; } virtual void getDefaultColor(GfxColor *color); virtual void getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel); // ICCBased-specific access. GfxColorSpace *getAlt() { return alt; } private: int nComps; // number of color components (1, 3, or 4) GfxColorSpace *alt; // alternate color space double rangeMin[4]; // min values for each component double rangeMax[4]; // max values for each component Ref iccProfileStream; // the ICC profile }; //------------------------------------------------------------------------ // GfxIndexedColorSpace //------------------------------------------------------------------------ class GfxIndexedColorSpace: public GfxColorSpace { public: GfxIndexedColorSpace(GfxColorSpace *baseA, int indexHighA); virtual ~GfxIndexedColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csIndexed; } // Construct an Indexed color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); virtual void getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel); // Indexed-specific access. GfxColorSpace *getBase() { return base; } int getIndexHigh() { return indexHigh; } Guchar *getLookup() { return lookup; } GfxColor *mapColorToBase(GfxColor *color, GfxColor *baseColor); private: GfxColorSpace *base; // base color space int indexHigh; // max pixel value Guchar *lookup; // lookup table }; //------------------------------------------------------------------------ // GfxSeparationColorSpace //------------------------------------------------------------------------ class GfxSeparationColorSpace: public GfxColorSpace { public: GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, Function *funcA); virtual ~GfxSeparationColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csSeparation; } // Construct a Separation color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } virtual void getDefaultColor(GfxColor *color); virtual GBool isNonMarking() { return nonMarking; } // Separation-specific access. GString *getName() { return name; } GfxColorSpace *getAlt() { return alt; } Function *getFunc() { return func; } private: GfxSeparationColorSpace(GString *nameA, GfxColorSpace *altA, Function *funcA, GBool nonMarkingA, Guint overprintMaskA); GString *name; // colorant name GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) GBool nonMarking; }; //------------------------------------------------------------------------ // GfxDeviceNColorSpace //------------------------------------------------------------------------ class GfxDeviceNColorSpace: public GfxColorSpace { public: GfxDeviceNColorSpace(int nCompsA, GString **namesA, GfxColorSpace *alt, Function *func); virtual ~GfxDeviceNColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csDeviceN; } // Construct a DeviceN color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return nComps; } virtual void getDefaultColor(GfxColor *color); virtual GBool isNonMarking() { return nonMarking; } // DeviceN-specific access. GString *getColorantName(int i) { return names[i]; } GfxColorSpace *getAlt() { return alt; } Function *getTintTransformFunc() { return func; } private: GfxDeviceNColorSpace(int nCompsA, GString **namesA, GfxColorSpace *alt, Function *func, GBool nonMarkingA, Guint overprintMaskA); int nComps; // number of components GString // colorant names *names[gfxColorMaxComps]; GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) GBool nonMarking; }; //------------------------------------------------------------------------ // GfxPatternColorSpace //------------------------------------------------------------------------ class GfxPatternColorSpace: public GfxColorSpace { public: GfxPatternColorSpace(GfxColorSpace *underA); virtual ~GfxPatternColorSpace(); virtual GfxColorSpace *copy(); virtual GfxColorSpaceMode getMode() { return csPattern; } // Construct a Pattern color space. Returns NULL if unsuccessful. static GfxColorSpace *parse(Array *arr, int recursion); virtual void getGray(GfxColor *color, GfxGray *gray); virtual void getRGB(GfxColor *color, GfxRGB *rgb); virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 0; } virtual void getDefaultColor(GfxColor *color); // Pattern-specific access. GfxColorSpace *getUnder() { return under; } private: GfxColorSpace *under; // underlying color space (for uncolored // patterns) }; //------------------------------------------------------------------------ // GfxPattern //------------------------------------------------------------------------ class GfxPattern { public: GfxPattern(int typeA); virtual ~GfxPattern(); static GfxPattern *parse(Object *obj); virtual GfxPattern *copy() = 0; int getType() { return type; } private: int type; }; //------------------------------------------------------------------------ // GfxTilingPattern //------------------------------------------------------------------------ class GfxTilingPattern: public GfxPattern { public: static GfxTilingPattern *parse(Object *patObj); virtual ~GfxTilingPattern(); virtual GfxPattern *copy(); int getPaintType() { return paintType; } int getTilingType() { return tilingType; } double *getBBox() { return bbox; } double getXStep() { return xStep; } double getYStep() { return yStep; } Dict *getResDict() { return resDict.isDict() ? resDict.getDict() : (Dict *)NULL; } double *getMatrix() { return matrix; } Object *getContentStream() { return &contentStream; } private: GfxTilingPattern(int paintTypeA, int tilingTypeA, double *bboxA, double xStepA, double yStepA, Object *resDictA, double *matrixA, Object *contentStreamA); int paintType; int tilingType; double bbox[4]; double xStep, yStep; Object resDict; double matrix[6]; Object contentStream; }; //------------------------------------------------------------------------ // GfxShadingPattern //------------------------------------------------------------------------ class GfxShadingPattern: public GfxPattern { public: static GfxShadingPattern *parse(Object *patObj); virtual ~GfxShadingPattern(); virtual GfxPattern *copy(); GfxShading *getShading() { return shading; } double *getMatrix() { return matrix; } private: GfxShadingPattern(GfxShading *shadingA, double *matrixA); GfxShading *shading; double matrix[6]; }; //------------------------------------------------------------------------ // GfxShading //------------------------------------------------------------------------ class GfxShading { public: GfxShading(int typeA); GfxShading(GfxShading *shading); virtual ~GfxShading(); static GfxShading *parse(Object *obj); virtual GfxShading *copy() = 0; int getType() { return type; } GfxColorSpace *getColorSpace() { return colorSpace; } GfxColor *getBackground() { return &background; } GBool getHasBackground() { return hasBackground; } void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } GBool getHasBBox() { return hasBBox; } protected: GBool init(Dict *dict); int type; GfxColorSpace *colorSpace; GfxColor background; GBool hasBackground; double xMin, yMin, xMax, yMax; GBool hasBBox; }; //------------------------------------------------------------------------ // GfxFunctionShading //------------------------------------------------------------------------ class GfxFunctionShading: public GfxShading { public: GfxFunctionShading(double x0A, double y0A, double x1A, double y1A, double *matrixA, Function **funcsA, int nFuncsA); GfxFunctionShading(GfxFunctionShading *shading); virtual ~GfxFunctionShading(); static GfxFunctionShading *parse(Dict *dict); virtual GfxShading *copy(); void getDomain(double *x0A, double *y0A, double *x1A, double *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double *getMatrix() { return matrix; } int getNFuncs() { return nFuncs; } Function *getFunc(int i) { return funcs[i]; } void getColor(double x, double y, GfxColor *color); private: double x0, y0, x1, y1; double matrix[6]; Function *funcs[gfxColorMaxComps]; int nFuncs; }; //------------------------------------------------------------------------ // GfxAxialShading //------------------------------------------------------------------------ class GfxAxialShading: public GfxShading { public: GfxAxialShading(double x0A, double y0A, double x1A, double y1A, double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A); GfxAxialShading(GfxAxialShading *shading); virtual ~GfxAxialShading(); static GfxAxialShading *parse(Dict *dict); virtual GfxShading *copy(); void getCoords(double *x0A, double *y0A, double *x1A, double *y1A) { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; } double getDomain0() { return t0; } double getDomain1() { return t1; } GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } int getNFuncs() { return nFuncs; } Function *getFunc(int i) { return funcs[i]; } void getColor(double t, GfxColor *color); private: double x0, y0, x1, y1; double t0, t1; Function *funcs[gfxColorMaxComps]; int nFuncs; GBool extend0, extend1; }; //------------------------------------------------------------------------ // GfxRadialShading //------------------------------------------------------------------------ class GfxRadialShading: public GfxShading { public: GfxRadialShading(double x0A, double y0A, double r0A, double x1A, double y1A, double r1A, double t0A, double t1A, Function **funcsA, int nFuncsA, GBool extend0A, GBool extend1A); GfxRadialShading(GfxRadialShading *shading); virtual ~GfxRadialShading(); static GfxRadialShading *parse(Dict *dict); virtual GfxShading *copy(); void getCoords(double *x0A, double *y0A, double *r0A, double *x1A, double *y1A, double *r1A) { *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; } double getDomain0() { return t0; } double getDomain1() { return t1; } GBool getExtend0() { return extend0; } GBool getExtend1() { return extend1; } int getNFuncs() { return nFuncs; } Function *getFunc(int i) { return funcs[i]; } void getColor(double t, GfxColor *color); private: double x0, y0, r0, x1, y1, r1; double t0, t1; Function *funcs[gfxColorMaxComps]; int nFuncs; GBool extend0, extend1; }; //------------------------------------------------------------------------ // GfxGouraudTriangleShading //------------------------------------------------------------------------ struct GfxGouraudVertex { double x, y; GfxColor color; }; class GfxGouraudTriangleShading: public GfxShading { public: GfxGouraudTriangleShading(int typeA, GfxGouraudVertex *verticesA, int nVerticesA, int (*trianglesA)[3], int nTrianglesA, Function **funcsA, int nFuncsA); GfxGouraudTriangleShading(GfxGouraudTriangleShading *shading); virtual ~GfxGouraudTriangleShading(); static GfxGouraudTriangleShading *parse(int typeA, Dict *dict, Stream *str); virtual GfxShading *copy(); int getNTriangles() { return nTriangles; } void getTriangle(int i, double *x0, double *y0, GfxColor *color0, double *x1, double *y1, GfxColor *color1, double *x2, double *y2, GfxColor *color2); private: GfxGouraudVertex *vertices; int nVertices; int (*triangles)[3]; int nTriangles; Function *funcs[gfxColorMaxComps]; int nFuncs; }; //------------------------------------------------------------------------ // GfxPatchMeshShading //------------------------------------------------------------------------ struct GfxPatch { double x[4][4]; double y[4][4]; GfxColor color[2][2]; }; class GfxPatchMeshShading: public GfxShading { public: GfxPatchMeshShading(int typeA, GfxPatch *patchesA, int nPatchesA, Function **funcsA, int nFuncsA); GfxPatchMeshShading(GfxPatchMeshShading *shading); virtual ~GfxPatchMeshShading(); static GfxPatchMeshShading *parse(int typeA, Dict *dict, Stream *str); virtual GfxShading *copy(); int getNPatches() { return nPatches; } GfxPatch *getPatch(int i) { return &patches[i]; } private: GfxPatch *patches; int nPatches; Function *funcs[gfxColorMaxComps]; int nFuncs; }; //------------------------------------------------------------------------ // GfxImageColorMap //------------------------------------------------------------------------ class GfxImageColorMap { public: // Constructor. GfxImageColorMap(int bitsA, Object *decode, GfxColorSpace *colorSpaceA); // Destructor. ~GfxImageColorMap(); // Return a copy of this color map. GfxImageColorMap *copy() { return new GfxImageColorMap(this); } // Is color map valid? GBool isOk() { return ok; } // Get the color space. GfxColorSpace *getColorSpace() { return colorSpace; } // Get stream decoding info. int getNumPixelComps() { return nComps; } int getBits() { return bits; } // Get decode table. double getDecodeLow(int i) { return decodeLow[i]; } double getDecodeHigh(int i) { return decodeLow[i] + decodeRange[i]; } // Convert an image pixel to a color. void getGray(Guchar *x, GfxGray *gray); void getRGB(Guchar *x, GfxRGB *rgb); void getCMYK(Guchar *x, GfxCMYK *cmyk); void getColor(Guchar *x, GfxColor *color); // Convert a line of pixels to 8-bit colors. void getGrayByteLine(Guchar *in, Guchar *out, int n); void getRGBByteLine(Guchar *in, Guchar *out, int n); void getCMYKByteLine(Guchar *in, Guchar *out, int n); private: GfxImageColorMap(GfxImageColorMap *colorMap); GfxColorSpace *colorSpace; // the image color space int bits; // bits per component int nComps; // number of components in a pixel GfxColorSpace *colorSpace2; // secondary color space int nComps2; // number of components in colorSpace2 GfxColorComp * // lookup table lookup[gfxColorMaxComps]; GfxColorComp * // optimized case lookup table lookup2[gfxColorMaxComps]; double // minimum values for each component decodeLow[gfxColorMaxComps]; double // max - min value for each component decodeRange[gfxColorMaxComps]; GBool ok; }; //------------------------------------------------------------------------ // GfxSubpath and GfxPath //------------------------------------------------------------------------ class GfxSubpath { public: // Constructor. GfxSubpath(double x1, double y1); // Destructor. ~GfxSubpath(); // Copy. GfxSubpath *copy() { return new GfxSubpath(this); } // Get points. int getNumPoints() { return n; } double getX(int i) { return x[i]; } double getY(int i) { return y[i]; } GBool getCurve(int i) { return curve[i]; } // Get last point. double getLastX() { return x[n-1]; } double getLastY() { return y[n-1]; } // Add a line segment. void lineTo(double x1, double y1); // Add a Bezier curve. void curveTo(double x1, double y1, double x2, double y2, double x3, double y3); // Close the subpath. void close(); GBool isClosed() { return closed; } // Add (, ) to each point in the subpath. void offset(double dx, double dy); private: double *x, *y; // points GBool *curve; // curve[i] => point i is a control point // for a Bezier curve int n; // number of points int size; // size of x/y arrays GBool closed; // set if path is closed GfxSubpath(GfxSubpath *subpath); }; class GfxPath { public: // Constructor. GfxPath(); // Destructor. ~GfxPath(); // Copy. GfxPath *copy() { return new GfxPath(justMoved, firstX, firstY, subpaths, n, size); } // Is there a current point? GBool isCurPt() { return n > 0 || justMoved; } // Is the path non-empty, i.e., is there at least one segment? GBool isPath() { return n > 0; } // Get subpaths. int getNumSubpaths() { return n; } GfxSubpath *getSubpath(int i) { return subpaths[i]; } // Get last point on last subpath. double getLastX() { return subpaths[n-1]->getLastX(); } double getLastY() { return subpaths[n-1]->getLastY(); } // Move the current point. void moveTo(double x, double y); // Add a segment to the last subpath. void lineTo(double x, double y); // Add a Bezier curve to the last subpath void curveTo(double x1, double y1, double x2, double y2, double x3, double y3); // Close the last subpath. void close(); // Append to . void append(GfxPath *path); // Add (, ) to each point in the path. void offset(double dx, double dy); private: GBool justMoved; // set if a new subpath was just started double firstX, firstY; // first point in new subpath GfxSubpath **subpaths; // subpaths int n; // number of subpaths int size; // size of subpaths array GfxPath(GBool justMoved1, double firstX1, double firstY1, GfxSubpath **subpaths1, int n1, int size1); }; //------------------------------------------------------------------------ // GfxState //------------------------------------------------------------------------ class GfxState { public: // Construct a default GfxState, for a device with resolution // x , page box , page rotation , and // coordinate system specified by . GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, int rotateA, GBool upsideDown); // Destructor. ~GfxState(); // Copy. GfxState *copy(GBool copyPath = gFalse) { return new GfxState(this, copyPath); } // Accessors. double getHDPI() { return hDPI; } double getVDPI() { return vDPI; } double *getCTM() { return ctm; } double getX1() { return px1; } double getY1() { return py1; } double getX2() { return px2; } double getY2() { return py2; } double getPageWidth() { return pageWidth; } double getPageHeight() { return pageHeight; } int getRotate() { return rotate; } GfxColor *getFillColor() { return &fillColor; } GfxColor *getStrokeColor() { return &strokeColor; } void getFillGray(GfxGray *gray) { fillColorSpace->getGray(&fillColor, gray); } void getStrokeGray(GfxGray *gray) { strokeColorSpace->getGray(&strokeColor, gray); } void getFillRGB(GfxRGB *rgb) { fillColorSpace->getRGB(&fillColor, rgb); } void getStrokeRGB(GfxRGB *rgb) { strokeColorSpace->getRGB(&strokeColor, rgb); } void getFillCMYK(GfxCMYK *cmyk) { fillColorSpace->getCMYK(&fillColor, cmyk); } void getStrokeCMYK(GfxCMYK *cmyk) { strokeColorSpace->getCMYK(&strokeColor, cmyk); } GfxColorSpace *getFillColorSpace() { return fillColorSpace; } GfxColorSpace *getStrokeColorSpace() { return strokeColorSpace; } GfxPattern *getFillPattern() { return fillPattern; } GfxPattern *getStrokePattern() { return strokePattern; } GfxBlendMode getBlendMode() { return blendMode; } double getFillOpacity() { return fillOpacity; } double getStrokeOpacity() { return strokeOpacity; } GBool getFillOverprint() { return fillOverprint; } GBool getStrokeOverprint() { return strokeOverprint; } int getOverprintMode() { return overprintMode; } Function **getTransfer() { return transfer; } double getLineWidth() { return lineWidth; } void getLineDash(double **dash, int *length, double *start) { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } int getFlatness() { return flatness; } int getLineJoin() { return lineJoin; } int getLineCap() { return lineCap; } double getMiterLimit() { return miterLimit; } GBool getStrokeAdjust() { return strokeAdjust; } GfxFont *getFont() { return font; } double getFontSize() { return fontSize; } double *getTextMat() { return textMat; } double getCharSpace() { return charSpace; } double getWordSpace() { return wordSpace; } double getHorizScaling() { return horizScaling; } double getLeading() { return leading; } double getRise() { return rise; } int getRender() { return render; } GfxPath *getPath() { return path; } void setPath(GfxPath *pathA); double getCurX() { return curX; } double getCurY() { return curY; } void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) { *xMin = clipXMin; *yMin = clipYMin; *xMax = clipXMax; *yMax = clipYMax; } void getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax); double getLineX() { return lineX; } double getLineY() { return lineY; } // Is there a current point/path? GBool isCurPt() { return path->isCurPt(); } GBool isPath() { return path->isPath(); } // Transforms. void transform(double x1, double y1, double *x2, double *y2) { *x2 = ctm[0] * x1 + ctm[2] * y1 + ctm[4]; *y2 = ctm[1] * x1 + ctm[3] * y1 + ctm[5]; } void transformDelta(double x1, double y1, double *x2, double *y2) { *x2 = ctm[0] * x1 + ctm[2] * y1; *y2 = ctm[1] * x1 + ctm[3] * y1; } void textTransform(double x1, double y1, double *x2, double *y2) { *x2 = textMat[0] * x1 + textMat[2] * y1 + textMat[4]; *y2 = textMat[1] * x1 + textMat[3] * y1 + textMat[5]; } void textTransformDelta(double x1, double y1, double *x2, double *y2) { *x2 = textMat[0] * x1 + textMat[2] * y1; *y2 = textMat[1] * x1 + textMat[3] * y1; } double transformWidth(double w); double getTransformedLineWidth() { return transformWidth(lineWidth); } double getTransformedFontSize(); void getFontTransMat(double *m11, double *m12, double *m21, double *m22); // Change state parameters. void setCTM(double a, double b, double c, double d, double e, double f); void concatCTM(double a, double b, double c, double d, double e, double f); void shiftCTM(double tx, double ty); void setFillColorSpace(GfxColorSpace *colorSpace); void setStrokeColorSpace(GfxColorSpace *colorSpace); void setFillColor(GfxColor *color) { fillColor = *color; } void setStrokeColor(GfxColor *color) { strokeColor = *color; } void setFillPattern(GfxPattern *pattern); void setStrokePattern(GfxPattern *pattern); void setBlendMode(GfxBlendMode mode) { blendMode = mode; } void setFillOpacity(double opac) { fillOpacity = opac; } void setStrokeOpacity(double opac) { strokeOpacity = opac; } void setFillOverprint(GBool op) { fillOverprint = op; } void setStrokeOverprint(GBool op) { strokeOverprint = op; } void setOverprintMode(int opm) { overprintMode = opm; } void setTransfer(Function **funcs); void setLineWidth(double width) { lineWidth = width; } void setLineDash(double *dash, int length, double start); void setFlatness(int flatness1) { flatness = flatness1; } void setLineJoin(int lineJoin1) { lineJoin = lineJoin1; } void setLineCap(int lineCap1) { lineCap = lineCap1; } void setMiterLimit(double limit) { miterLimit = limit; } void setStrokeAdjust(GBool sa) { strokeAdjust = sa; } void setFont(GfxFont *fontA, double fontSizeA) { font = fontA; fontSize = fontSizeA; } void setTextMat(double a, double b, double c, double d, double e, double f) { textMat[0] = a; textMat[1] = b; textMat[2] = c; textMat[3] = d; textMat[4] = e; textMat[5] = f; } void setCharSpace(double space) { charSpace = space; } void setWordSpace(double space) { wordSpace = space; } void setHorizScaling(double scale) { horizScaling = 0.01 * scale; } void setLeading(double leadingA) { leading = leadingA; } void setRise(double riseA) { rise = riseA; } void setRender(int renderA) { render = renderA; } // Add to path. void moveTo(double x, double y) { path->moveTo(curX = x, curY = y); } void lineTo(double x, double y) { path->lineTo(curX = x, curY = y); } void curveTo(double x1, double y1, double x2, double y2, double x3, double y3) { path->curveTo(x1, y1, x2, y2, curX = x3, curY = y3); } void closePath() { path->close(); curX = path->getLastX(); curY = path->getLastY(); } void clearPath(); // Update clip region. void clip(); void clipToStrokePath(); void clipToRect(double xMin, double yMin, double xMax, double yMax); // Text position. void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } void textMoveTo(double tx, double ty) { lineX = tx; lineY = ty; textTransform(tx, ty, &curX, &curY); } void textShift(double tx, double ty); void shift(double dx, double dy); // Push/pop GfxState on/off stack. GfxState *save(); GfxState *restore(); GBool hasSaves() { return saved != NULL; } // Misc GBool parseBlendMode(Object *obj, GfxBlendMode *mode); private: double hDPI, vDPI; // resolution double ctm[6]; // coord transform matrix double px1, py1, px2, py2; // page corners (user coords) double pageWidth, pageHeight; // page size (pixels) int rotate; // page rotation angle GfxColorSpace *fillColorSpace; // fill color space GfxColorSpace *strokeColorSpace; // stroke color space GfxColor fillColor; // fill color GfxColor strokeColor; // stroke color GfxPattern *fillPattern; // fill pattern GfxPattern *strokePattern; // stroke pattern GfxBlendMode blendMode; // transparency blend mode double fillOpacity; // fill opacity double strokeOpacity; // stroke opacity GBool fillOverprint; // fill overprint GBool strokeOverprint; // stroke overprint int overprintMode; // overprint mode ("OPM") Function *transfer[4]; // transfer function (entries may be: all // NULL = identity; last three NULL = // single function; all four non-NULL = // R,G,B,gray functions) double lineWidth; // line width double *lineDash; // line dash int lineDashLength; double lineDashStart; int flatness; // curve flatness int lineJoin; // line join style int lineCap; // line cap style double miterLimit; // line miter limit GBool strokeAdjust; // stroke adjustment GfxFont *font; // font double fontSize; // font size double textMat[6]; // text matrix double charSpace; // character spacing double wordSpace; // word spacing double horizScaling; // horizontal scaling double leading; // text leading double rise; // text rise int render; // text rendering mode GfxPath *path; // array of path elements double curX, curY; // current point (user coords) double lineX, lineY; // start of current text line (text coords) double clipXMin, clipYMin, // bounding box for clip region clipXMax, clipYMax; GfxState *saved; // next GfxState on stack GfxState(GfxState *state, GBool copyPath); }; #endif xpdf-3.03/xpdf/Lexer.cc0000644000076400007640000002352211622305345014246 0ustar dereknderekn//======================================================================== // // Lexer.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include "Lexer.h" #include "Error.h" //------------------------------------------------------------------------ // A '1' in this array means the character is white space. A '1' or // '2' means the character ends a name or command. static char specialChars[256] = { 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx }; //------------------------------------------------------------------------ // Lexer //------------------------------------------------------------------------ Lexer::Lexer(XRef *xref, Stream *str) { Object obj; curStr.initStream(str); streams = new Array(xref); streams->add(curStr.copy(&obj)); strPtr = 0; freeArray = gTrue; curStr.streamReset(); } Lexer::Lexer(XRef *xref, Object *obj) { Object obj2; if (obj->isStream()) { streams = new Array(xref); freeArray = gTrue; streams->add(obj->copy(&obj2)); } else { streams = obj->getArray(); freeArray = gFalse; } strPtr = 0; if (streams->getLength() > 0) { streams->get(strPtr, &curStr); curStr.streamReset(); } } Lexer::~Lexer() { if (!curStr.isNone()) { curStr.streamClose(); curStr.free(); } if (freeArray) { delete streams; } } int Lexer::getChar() { int c; c = EOF; while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { curStr.streamClose(); curStr.free(); ++strPtr; if (strPtr < streams->getLength()) { streams->get(strPtr, &curStr); curStr.streamReset(); } } return c; } int Lexer::lookChar() { if (curStr.isNone()) { return EOF; } return curStr.streamLookChar(); } Object *Lexer::getObj(Object *obj) { char *p; int c, c2; GBool comment, neg, done; int numParen; int xi; double xf, scale; GString *s; int n, m; // skip whitespace and comments comment = gFalse; while (1) { if ((c = getChar()) == EOF) { return obj->initEOF(); } if (comment) { if (c == '\r' || c == '\n') comment = gFalse; } else if (c == '%') { comment = gTrue; } else if (specialChars[c] != 1) { break; } } // start reading token switch (c) { // number case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '-': case '.': neg = gFalse; xf = xi = 0; if (c == '-') { neg = gTrue; } else if (c == '.') { goto doReal; } else { xf = xi = c - '0'; } while (1) { c = lookChar(); if (isdigit(c)) { getChar(); xi = xi * 10 + (c - '0'); xf = xf * 10 + (c - '0'); } else if (c == '.') { getChar(); goto doReal; } else { break; } } if (neg) { xi = -xi; } obj->initInt(xi); break; doReal: scale = 0.1; while (1) { c = lookChar(); if (c == '-') { // ignore minus signs in the middle of numbers to match // Adobe's behavior error(errSyntaxWarning, getPos(), "Badly formatted number"); getChar(); continue; } if (!isdigit(c)) { break; } getChar(); xf = xf + scale * (c - '0'); scale *= 0.1; } if (neg) { xf = -xf; } obj->initReal(xf); break; // string case '(': p = tokBuf; n = 0; numParen = 1; done = gFalse; s = NULL; do { c2 = EOF; switch (c = getChar()) { case EOF: #if 0 // This breaks some PDF files, e.g., ones from Photoshop. case '\r': case '\n': #endif error(errSyntaxError, getPos(), "Unterminated string"); done = gTrue; break; case '(': ++numParen; c2 = c; break; case ')': if (--numParen == 0) { done = gTrue; } else { c2 = c; } break; case '\\': switch (c = getChar()) { case 'n': c2 = '\n'; break; case 'r': c2 = '\r'; break; case 't': c2 = '\t'; break; case 'b': c2 = '\b'; break; case 'f': c2 = '\f'; break; case '\\': case '(': case ')': c2 = c; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': c2 = c - '0'; c = lookChar(); if (c >= '0' && c <= '7') { getChar(); c2 = (c2 << 3) + (c - '0'); c = lookChar(); if (c >= '0' && c <= '7') { getChar(); c2 = (c2 << 3) + (c - '0'); } } break; case '\r': c = lookChar(); if (c == '\n') { getChar(); } break; case '\n': break; case EOF: error(errSyntaxError, getPos(), "Unterminated string"); done = gTrue; break; default: c2 = c; break; } break; default: c2 = c; break; } if (c2 != EOF) { if (n == tokBufSize) { if (!s) s = new GString(tokBuf, tokBufSize); else s->append(tokBuf, tokBufSize); p = tokBuf; n = 0; } *p++ = (char)c2; ++n; } } while (!done); if (!s) s = new GString(tokBuf, n); else s->append(tokBuf, n); obj->initString(s); break; // name case '/': p = tokBuf; n = 0; s = NULL; while ((c = lookChar()) != EOF && !specialChars[c]) { getChar(); if (c == '#') { c2 = lookChar(); if (c2 >= '0' && c2 <= '9') { c = c2 - '0'; } else if (c2 >= 'A' && c2 <= 'F') { c = c2 - 'A' + 10; } else if (c2 >= 'a' && c2 <= 'f') { c = c2 - 'a' + 10; } else { goto notEscChar; } getChar(); c <<= 4; c2 = getChar(); if (c2 >= '0' && c2 <= '9') { c += c2 - '0'; } else if (c2 >= 'A' && c2 <= 'F') { c += c2 - 'A' + 10; } else if (c2 >= 'a' && c2 <= 'f') { c += c2 - 'a' + 10; } else { error(errSyntaxError, getPos(), "Illegal digit in hex char in name"); } } notEscChar: // the PDF spec claims that names are limited to 127 chars, but // Distiller 8 will produce longer names, and Acrobat 8 will // accept longer names ++n; if (n < tokBufSize) { *p++ = c; } else if (n == tokBufSize) { *p = c; s = new GString(tokBuf, n); } else { s->append((char)c); } } if (n < tokBufSize) { *p = '\0'; obj->initName(tokBuf); } else { obj->initName(s->getCString()); delete s; } break; // array punctuation case '[': case ']': tokBuf[0] = c; tokBuf[1] = '\0'; obj->initCmd(tokBuf); break; // hex string or dict punctuation case '<': c = lookChar(); // dict punctuation if (c == '<') { getChar(); tokBuf[0] = tokBuf[1] = '<'; tokBuf[2] = '\0'; obj->initCmd(tokBuf); // hex string } else { p = tokBuf; m = n = 0; c2 = 0; s = NULL; while (1) { c = getChar(); if (c == '>') { break; } else if (c == EOF) { error(errSyntaxError, getPos(), "Unterminated hex string"); break; } else if (specialChars[c] != 1) { c2 = c2 << 4; if (c >= '0' && c <= '9') c2 += c - '0'; else if (c >= 'A' && c <= 'F') c2 += c - 'A' + 10; else if (c >= 'a' && c <= 'f') c2 += c - 'a' + 10; else error(errSyntaxError, getPos(), "Illegal character <{0:02x}> in hex string", c); if (++m == 2) { if (n == tokBufSize) { if (!s) s = new GString(tokBuf, tokBufSize); else s->append(tokBuf, tokBufSize); p = tokBuf; n = 0; } *p++ = (char)c2; ++n; c2 = 0; m = 0; } } } if (!s) s = new GString(tokBuf, n); else s->append(tokBuf, n); if (m == 1) s->append((char)(c2 << 4)); obj->initString(s); } break; // dict punctuation case '>': c = lookChar(); if (c == '>') { getChar(); tokBuf[0] = tokBuf[1] = '>'; tokBuf[2] = '\0'; obj->initCmd(tokBuf); } else { error(errSyntaxError, getPos(), "Illegal character '>'"); obj->initError(); } break; // error case ')': case '{': case '}': error(errSyntaxError, getPos(), "Illegal character '{0:c}'", c); obj->initError(); break; // command default: p = tokBuf; *p++ = c; n = 1; while ((c = lookChar()) != EOF && !specialChars[c]) { getChar(); if (++n == tokBufSize) { error(errSyntaxError, getPos(), "Command token too long"); break; } *p++ = c; } *p = '\0'; if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) { obj->initBool(gTrue); } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) { obj->initBool(gFalse); } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) { obj->initNull(); } else { obj->initCmd(tokBuf); } break; } return obj; } void Lexer::skipToNextLine() { int c; while (1) { c = getChar(); if (c == EOF || c == '\n') { return; } if (c == '\r') { if ((c = lookChar()) == '\n') { getChar(); } return; } } } GBool Lexer::isSpace(int c) { return c >= 0 && c <= 0xff && specialChars[c] == 1; } xpdf-3.03/xpdf/XPDFCore.h0000644000076400007640000001742711622305345014412 0ustar dereknderekn//======================================================================== // // XPDFCore.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XPDFCORE_H #define XPDFCORE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #define Object XtObject #include #undef Object #include "gtypes.h" #include "gfile.h" // for time_t #include "SplashTypes.h" #include "PDFCore.h" class GString; class BaseStream; class PDFDoc; class LinkAction; //------------------------------------------------------------------------ #define xMaxRGBCube 6 // max size of RGB color cube //------------------------------------------------------------------------ // callbacks //------------------------------------------------------------------------ typedef void (*XPDFUpdateCbk)(void *data, GString *fileName, int pageNum, int numPages, const char *linkLabel); typedef void (*XPDFActionCbk)(void *data, char *action); typedef void (*XPDFKeyPressCbk)(void *data, KeySym key, Guint modifiers, XEvent *event); typedef void (*XPDFMouseCbk)(void *data, XEvent *event); //------------------------------------------------------------------------ // XPDFCore //------------------------------------------------------------------------ class XPDFCore: public PDFCore { public: // Create viewer core inside . XPDFCore(Widget shellA, Widget parentWidgetA, SplashColorPtr paperColorA, Gulong paperPixelA, Gulong mattePixelA, GBool fullScreenA, GBool reverseVideoA, GBool installCmap, int rgbCubeSizeA); ~XPDFCore(); //----- loadFile / displayPage / displayDest // Load a new file. Returns pdfOk or error code. virtual int loadFile(GString *fileName, GString *ownerPassword = NULL, GString *userPassword = NULL); // Load a new file, via a Stream instead of a file name. Returns // pdfOk or error code. virtual int loadFile(BaseStream *stream, GString *ownerPassword = NULL, GString *userPassword = NULL); // Load an already-created PDFDoc object. virtual void loadDoc(PDFDoc *docA); // Resize the window to fit page of the current document. void resizeToPage(int pg); // Update the display, given the specified parameters. virtual void update(int topPageA, int scrollXA, int scrollYA, double zoomA, int rotateA, GBool force, GBool addToHist, GBool adjustScrollX); //----- page/position changes virtual GBool gotoNextPage(int inc, GBool top); virtual GBool gotoPrevPage(int dec, GBool top, GBool bottom); virtual GBool goForward(); virtual GBool goBackward(); void startPan(int wx, int wy); void endPan(int wx, int wy); //----- selection void startSelection(int wx, int wy); void endSelection(int wx, int wy); void copySelection(); //----- hyperlinks void doAction(LinkAction *action); LinkAction *getLinkAction() { return linkAction; } GString *mungeURL(GString *url); //----- find virtual GBool find(char *s, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly); virtual GBool findU(Unicode *u, int len, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly); //----- simple modal dialogs GBool doQuestionDialog(const char *title, GString *msg); void doInfoDialog(const char *title, GString *msg); void doErrorDialog(const char *title, GString *msg); //----- password dialog virtual GString *getPassword(); //----- misc access Widget getWidget() { return scrolledWin; } Widget getDrawAreaWidget() { return drawArea; } virtual void setBusyCursor(GBool busy); Cursor getBusyCursor() { return busyCursor; } void takeFocus(); void enableHyperlinks(GBool on) { hyperlinksEnabled = on; } GBool getHyperlinksEnabled() { return hyperlinksEnabled; } void enableSelect(GBool on) { selectEnabled = on; } void setUpdateCbk(XPDFUpdateCbk cbk, void *data) { updateCbk = cbk; updateCbkData = data; } void setActionCbk(XPDFActionCbk cbk, void *data) { actionCbk = cbk; actionCbkData = data; } void setKeyPressCbk(XPDFKeyPressCbk cbk, void *data) { keyPressCbk = cbk; keyPressCbkData = data; } void setMouseCbk(XPDFMouseCbk cbk, void *data) { mouseCbk = cbk; mouseCbkData = data; } GBool getFullScreen() { return fullScreen; } private: virtual GBool checkForNewFile(); //----- hyperlinks void runCommand(GString *cmdFmt, GString *arg); //----- selection static Boolean convertSelectionCbk(Widget widget, Atom *selection, Atom *target, Atom *type, XtPointer *value, unsigned long *length, int *format); //----- GUI code void setupX(GBool installCmap, int rgbCubeSizeA); void initWindow(); static void hScrollChangeCbk(Widget widget, XtPointer ptr, XtPointer callData); static void hScrollDragCbk(Widget widget, XtPointer ptr, XtPointer callData); static void vScrollChangeCbk(Widget widget, XtPointer ptr, XtPointer callData); static void vScrollDragCbk(Widget widget, XtPointer ptr, XtPointer callData); static void resizeCbk(Widget widget, XtPointer ptr, XtPointer callData); static void redrawCbk(Widget widget, XtPointer ptr, XtPointer callData); static void inputCbk(Widget widget, XtPointer ptr, XtPointer callData); virtual PDFCoreTile *newTile(int xDestA, int yDestA); virtual void updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc, int width, int height, GBool composited); virtual void redrawRect(PDFCoreTile *tileA, int xSrc, int ySrc, int xDest, int yDest, int width, int height, GBool composited); virtual void updateScrollbars(); void setCursor(Cursor cursor); GBool doDialog(int type, GBool hasCancel, const char *title, GString *msg); static void dialogOkCbk(Widget widget, XtPointer ptr, XtPointer callData); static void dialogCancelCbk(Widget widget, XtPointer ptr, XtPointer callData); void initPasswordDialog(); static void passwordTextVerifyCbk(Widget widget, XtPointer ptr, XtPointer callData); static void passwordOkCbk(Widget widget, XtPointer ptr, XtPointer callData); static void passwordCancelCbk(Widget widget, XtPointer ptr, XtPointer callData); Gulong paperPixel; Gulong mattePixel; //~unimp: move fullScreen into PDFCore? GBool fullScreen; Display *display; int screenNum; Visual *visual; Colormap colormap; Guint depth; // visual depth GBool trueColor; // set if using a TrueColor visual int rDiv, gDiv, bDiv; // RGB right shifts (for TrueColor) int rShift, gShift, bShift; // RGB left shifts (for TrueColor) int rgbCubeSize; // size of color cube (for non-TrueColor) Gulong // color cube (for non-TrueColor) colors[xMaxRGBCube * xMaxRGBCube * xMaxRGBCube]; Widget shell; // top-level shell containing the widget Widget parentWidget; // parent widget (not created by XPDFCore) Widget scrolledWin; Widget hScrollBar; Widget vScrollBar; Widget drawAreaFrame; Widget drawArea; Cursor busyCursor, linkCursor, selectCursor; Cursor currentCursor; GC drawAreaGC; // GC for blitting into drawArea static GString *currentSelection; // selected text static XPDFCore *currentSelectionOwner; static Atom targetsAtom; GBool panning; int panMX, panMY; time_t modTime; // last modification time of PDF file LinkAction *linkAction; // mouse cursor is over this link XPDFUpdateCbk updateCbk; void *updateCbkData; XPDFActionCbk actionCbk; void *actionCbkData; XPDFKeyPressCbk keyPressCbk; void *keyPressCbkData; XPDFMouseCbk mouseCbk; void *mouseCbkData; GBool hyperlinksEnabled; GBool selectEnabled; int dialogDone; Widget passwordDialog; Widget passwordText; GString *password; }; #endif xpdf-3.03/xpdf/rightArrow.xbm0000644000076400007640000000030411622305345015511 0ustar dereknderekn#define rightArrow_width 8 #define rightArrow_height 15 static unsigned char rightArrow_bits[] = { 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; xpdf-3.03/xpdf/SecurityHandler.cc0000644000076400007640000002742511622305345016302 0ustar dereknderekn//======================================================================== // // SecurityHandler.cc // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "GString.h" #include "PDFDoc.h" #include "Decrypt.h" #include "Error.h" #include "GlobalParams.h" #include "PDFCore.h" #ifdef ENABLE_PLUGINS # include "XpdfPluginAPI.h" #endif #include "SecurityHandler.h" //------------------------------------------------------------------------ // SecurityHandler //------------------------------------------------------------------------ SecurityHandler *SecurityHandler::make(PDFDoc *docA, Object *encryptDictA) { Object filterObj; SecurityHandler *secHdlr; #ifdef ENABLE_PLUGINS XpdfSecurityHandler *xsh; #endif encryptDictA->dictLookup("Filter", &filterObj); if (filterObj.isName("Standard")) { secHdlr = new StandardSecurityHandler(docA, encryptDictA); } else if (filterObj.isName()) { #ifdef ENABLE_PLUGINS if ((xsh = globalParams->getSecurityHandler(filterObj.getName()))) { secHdlr = new ExternalSecurityHandler(docA, encryptDictA, xsh); } else { #endif error(errSyntaxError, -1, "Couldn't find the '{0:s}' security handler", filterObj.getName()); secHdlr = NULL; #ifdef ENABLE_PLUGINS } #endif } else { error(errSyntaxError, -1, "Missing or invalid 'Filter' entry in encryption dictionary"); secHdlr = NULL; } filterObj.free(); return secHdlr; } SecurityHandler::SecurityHandler(PDFDoc *docA) { doc = docA; } SecurityHandler::~SecurityHandler() { } GBool SecurityHandler::checkEncryption(GString *ownerPassword, GString *userPassword) { void *authData; GBool ok; int i; if (ownerPassword || userPassword) { authData = makeAuthData(ownerPassword, userPassword); } else { authData = NULL; } ok = authorize(authData); if (authData) { freeAuthData(authData); } for (i = 0; !ok && i < 3; ++i) { if (!(authData = getAuthData())) { break; } ok = authorize(authData); if (authData) { freeAuthData(authData); } } if (!ok) { error(errCommandLine, -1, "Incorrect password"); } return ok; } //------------------------------------------------------------------------ // StandardSecurityHandler //------------------------------------------------------------------------ class StandardAuthData { public: StandardAuthData(GString *ownerPasswordA, GString *userPasswordA) { ownerPassword = ownerPasswordA; userPassword = userPasswordA; } ~StandardAuthData() { if (ownerPassword) { delete ownerPassword; } if (userPassword) { delete userPassword; } } GString *ownerPassword; GString *userPassword; }; StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, Object *encryptDictA): SecurityHandler(docA) { Object versionObj, revisionObj, lengthObj; Object ownerKeyObj, userKeyObj, ownerEncObj, userEncObj; Object permObj, fileIDObj, fileIDObj1; Object cryptFiltersObj, streamFilterObj, stringFilterObj; Object cryptFilterObj, cfmObj, cfLengthObj; Object encryptMetadataObj; ok = gFalse; fileID = NULL; ownerKey = NULL; userKey = NULL; ownerEnc = NULL; userEnc = NULL; fileKeyLength = 0; encryptDictA->dictLookup("V", &versionObj); encryptDictA->dictLookup("R", &revisionObj); encryptDictA->dictLookup("Length", &lengthObj); encryptDictA->dictLookup("O", &ownerKeyObj); encryptDictA->dictLookup("U", &userKeyObj); encryptDictA->dictLookup("OE", &ownerEncObj); encryptDictA->dictLookup("UE", &userEncObj); encryptDictA->dictLookup("P", &permObj); doc->getXRef()->getTrailerDict()->dictLookup("ID", &fileIDObj); if (versionObj.isInt() && revisionObj.isInt() && permObj.isInt() && ownerKeyObj.isString() && userKeyObj.isString()) { encVersion = versionObj.getInt(); encRevision = revisionObj.getInt(); if ((encRevision <= 4 && ownerKeyObj.getString()->getLength() == 32 && userKeyObj.getString()->getLength() == 32) || (encRevision == 5 && // the spec says 48 bytes, but Acrobat pads them out longer ownerKeyObj.getString()->getLength() >= 48 && userKeyObj.getString()->getLength() >= 48 && ownerEncObj.isString() && ownerEncObj.getString()->getLength() == 32 && userEncObj.isString() && userEncObj.getString()->getLength() == 32)) { encAlgorithm = cryptRC4; // revision 2 forces a 40-bit key - some buggy PDF generators // set the Length value incorrectly if (encRevision == 2 || !lengthObj.isInt()) { fileKeyLength = 5; } else { fileKeyLength = lengthObj.getInt() / 8; } encryptMetadata = gTrue; //~ this currently only handles a subset of crypt filter functionality //~ (in particular, it ignores the EFF entry in encryptDictA, and //~ doesn't handle the case where StmF, StrF, and EFF are not all the //~ same) if ((encVersion == 4 || encVersion == 5) && (encRevision == 4 || encRevision == 5)) { encryptDictA->dictLookup("CF", &cryptFiltersObj); encryptDictA->dictLookup("StmF", &streamFilterObj); encryptDictA->dictLookup("StrF", &stringFilterObj); if (cryptFiltersObj.isDict() && streamFilterObj.isName() && stringFilterObj.isName() && !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { if (!strcmp(streamFilterObj.getName(), "Identity")) { // no encryption on streams or strings encVersion = encRevision = -1; } else { if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), &cryptFilterObj)->isDict()) { cryptFilterObj.dictLookup("CFM", &cfmObj); if (cfmObj.isName("V2")) { encVersion = 2; encRevision = 3; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { //~ according to the spec, this should be cfLengthObj / 8 fileKeyLength = cfLengthObj.getInt(); } cfLengthObj.free(); } else if (cfmObj.isName("AESV2")) { encVersion = 2; encRevision = 3; encAlgorithm = cryptAES; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { //~ according to the spec, this should be cfLengthObj / 8 fileKeyLength = cfLengthObj.getInt(); } cfLengthObj.free(); } else if (cfmObj.isName("AESV3")) { encVersion = 5; encRevision = 5; encAlgorithm = cryptAES256; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { //~ according to the spec, this should be cfLengthObj / 8 fileKeyLength = cfLengthObj.getInt(); } cfLengthObj.free(); } cfmObj.free(); } cryptFilterObj.free(); } } stringFilterObj.free(); streamFilterObj.free(); cryptFiltersObj.free(); if (encryptDictA->dictLookup("EncryptMetadata", &encryptMetadataObj)->isBool()) { encryptMetadata = encryptMetadataObj.getBool(); } encryptMetadataObj.free(); } permFlags = permObj.getInt(); ownerKey = ownerKeyObj.getString()->copy(); userKey = userKeyObj.getString()->copy(); if (encVersion >= 1 && encVersion <= 2 && encRevision >= 2 && encRevision <= 3) { if (fileIDObj.isArray()) { if (fileIDObj.arrayGet(0, &fileIDObj1)->isString()) { fileID = fileIDObj1.getString()->copy(); } else { fileID = new GString(); } fileIDObj1.free(); } else { fileID = new GString(); } if (fileKeyLength > 16 || fileKeyLength < 0) { fileKeyLength = 16; } ok = gTrue; } else if (encVersion == 5 && encRevision == 5) { fileID = new GString(); // unused for V=R=5 ownerEnc = ownerEncObj.getString()->copy(); userEnc = userEncObj.getString()->copy(); if (fileKeyLength > 32 || fileKeyLength < 0) { fileKeyLength = 32; } ok = gTrue; } else if (!(encVersion == -1 && encRevision == -1)) { error(errUnimplemented, -1, "Unsupported version/revision ({0:d}/{1:d}) of Standard security handler", encVersion, encRevision); } } else { error(errSyntaxError, -1, "Invalid encryption key length"); } } else { error(errSyntaxError, -1, "Weird encryption info"); } fileIDObj.free(); permObj.free(); userEncObj.free(); ownerEncObj.free(); userKeyObj.free(); ownerKeyObj.free(); lengthObj.free(); revisionObj.free(); versionObj.free(); } StandardSecurityHandler::~StandardSecurityHandler() { if (fileID) { delete fileID; } if (ownerKey) { delete ownerKey; } if (userKey) { delete userKey; } if (ownerEnc) { delete ownerEnc; } if (userEnc) { delete userEnc; } } GBool StandardSecurityHandler::isUnencrypted() { return encVersion == -1 && encRevision == -1; } void *StandardSecurityHandler::makeAuthData(GString *ownerPassword, GString *userPassword) { return new StandardAuthData(ownerPassword ? ownerPassword->copy() : (GString *)NULL, userPassword ? userPassword->copy() : (GString *)NULL); } void *StandardSecurityHandler::getAuthData() { PDFCore *core; GString *password; if (!(core = doc->getCore()) || !(password = core->getPassword())) { return NULL; } return new StandardAuthData(password, password->copy()); } void StandardSecurityHandler::freeAuthData(void *authData) { delete (StandardAuthData *)authData; } GBool StandardSecurityHandler::authorize(void *authData) { GString *ownerPassword, *userPassword; if (!ok) { return gFalse; } if (authData) { ownerPassword = ((StandardAuthData *)authData)->ownerPassword; userPassword = ((StandardAuthData *)authData)->userPassword; } else { ownerPassword = NULL; userPassword = NULL; } if (!Decrypt::makeFileKey(encVersion, encRevision, fileKeyLength, ownerKey, userKey, ownerEnc, userEnc, permFlags, fileID, ownerPassword, userPassword, fileKey, encryptMetadata, &ownerPasswordOk)) { return gFalse; } return gTrue; } #ifdef ENABLE_PLUGINS //------------------------------------------------------------------------ // ExternalSecurityHandler //------------------------------------------------------------------------ ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, Object *encryptDictA, XpdfSecurityHandler *xshA): SecurityHandler(docA) { encryptDictA->copy(&encryptDict); xsh = xshA; encAlgorithm = cryptRC4; //~ this should be obtained via getKey ok = gFalse; if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, (XpdfObject)encryptDictA, &docData)) { return; } ok = gTrue; } ExternalSecurityHandler::~ExternalSecurityHandler() { (*xsh->freeDoc)(xsh->handlerData, docData); encryptDict.free(); } void *ExternalSecurityHandler::makeAuthData(GString *ownerPassword, GString *userPassword) { char *opw, *upw; void *authData; opw = ownerPassword ? ownerPassword->getCString() : (char *)NULL; upw = userPassword ? userPassword->getCString() : (char *)NULL; if (!(*xsh->makeAuthData)(xsh->handlerData, docData, opw, upw, &authData)) { return NULL; } return authData; } void *ExternalSecurityHandler::getAuthData() { void *authData; if (!(*xsh->getAuthData)(xsh->handlerData, docData, &authData)) { return NULL; } return authData; } void ExternalSecurityHandler::freeAuthData(void *authData) { (*xsh->freeAuthData)(xsh->handlerData, docData, authData); } GBool ExternalSecurityHandler::authorize(void *authData) { char *key; int length; if (!ok) { return gFalse; } permFlags = (*xsh->authorize)(xsh->handlerData, docData, authData); if (!(permFlags & xpdfPermissionOpen)) { return gFalse; } if (!(*xsh->getKey)(xsh->handlerData, docData, &key, &length, &encVersion)) { return gFalse; } if ((fileKeyLength = length) > 16) { fileKeyLength = 16; } memcpy(fileKey, key, fileKeyLength); (*xsh->freeKey)(xsh->handlerData, docData, key, length); return gTrue; } #endif // ENABLE_PLUGINS xpdf-3.03/xpdf/GlobalParams.cc0000644000076400007640000023471311622305345015541 0ustar dereknderekn//======================================================================== // // GlobalParams.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #ifdef ENABLE_PLUGINS # ifndef WIN32 # include # endif #endif #ifdef WIN32 # include #endif #if HAVE_PAPER_H #include #endif #include "gmem.h" #include "GString.h" #include "GList.h" #include "GHash.h" #include "gfile.h" #include "Error.h" #include "NameToCharCode.h" #include "CharCodeToUnicode.h" #include "UnicodeMap.h" #include "CMap.h" #include "BuiltinFontTables.h" #include "FontEncodingTables.h" #ifdef ENABLE_PLUGINS # include "XpdfPluginAPI.h" #endif #include "GlobalParams.h" #ifdef WIN32 # define strcasecmp stricmp #endif #if MULTITHREADED # define lockGlobalParams gLockMutex(&mutex) # define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) # define lockCMapCache gLockMutex(&cMapCacheMutex) # define unlockGlobalParams gUnlockMutex(&mutex) # define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex) # define unlockCMapCache gUnlockMutex(&cMapCacheMutex) #else # define lockGlobalParams # define lockUnicodeMapCache # define lockCMapCache # define unlockGlobalParams # define unlockUnicodeMapCache # define unlockCMapCache #endif #include "NameToUnicodeTable.h" #include "UnicodeMapTables.h" #include "UTF8.h" #ifdef ENABLE_PLUGINS # ifdef WIN32 extern XpdfPluginVecTable xpdfPluginVecTable; # endif #endif //------------------------------------------------------------------------ #define cidToUnicodeCacheSize 4 #define unicodeToUnicodeCacheSize 4 //------------------------------------------------------------------------ static struct { const char *name; const char *t1FileName; const char *ttFileName; } displayFontTab[] = { {"Courier", "n022003l.pfb", "cour.ttf"}, {"Courier-Bold", "n022004l.pfb", "courbd.ttf"}, {"Courier-BoldOblique", "n022024l.pfb", "courbi.ttf"}, {"Courier-Oblique", "n022023l.pfb", "couri.ttf"}, {"Helvetica", "n019003l.pfb", "arial.ttf"}, {"Helvetica-Bold", "n019004l.pfb", "arialbd.ttf"}, {"Helvetica-BoldOblique", "n019024l.pfb", "arialbi.ttf"}, {"Helvetica-Oblique", "n019023l.pfb", "ariali.ttf"}, {"Symbol", "s050000l.pfb", NULL}, {"Times-Bold", "n021004l.pfb", "timesbd.ttf"}, {"Times-BoldItalic", "n021024l.pfb", "timesbi.ttf"}, {"Times-Italic", "n021023l.pfb", "timesi.ttf"}, {"Times-Roman", "n021003l.pfb", "times.ttf"}, {"ZapfDingbats", "d050000l.pfb", NULL}, {NULL} }; #ifdef WIN32 static const char *displayFontDirs[] = { "c:/windows/fonts", "c:/winnt/fonts", NULL }; #else static const char *displayFontDirs[] = { "/usr/share/ghostscript/fonts", "/usr/local/share/ghostscript/fonts", "/usr/share/fonts/default/Type1", "/usr/share/fonts/default/ghostscript", "/usr/share/fonts/type1/gsfonts", NULL }; #endif //------------------------------------------------------------------------ GlobalParams *globalParams = NULL; //------------------------------------------------------------------------ // PSFontParam16 //------------------------------------------------------------------------ PSFontParam16::PSFontParam16(GString *nameA, int wModeA, GString *psFontNameA, GString *encodingA) { name = nameA; wMode = wModeA; psFontName = psFontNameA; encoding = encodingA; } PSFontParam16::~PSFontParam16() { delete name; delete psFontName; delete encoding; } //------------------------------------------------------------------------ // SysFontInfo //------------------------------------------------------------------------ class SysFontInfo { public: GString *name; GBool bold; GBool italic; GString *path; SysFontType type; int fontNum; // for TrueType collections SysFontInfo(GString *nameA, GBool boldA, GBool italicA, GString *pathA, SysFontType typeA, int fontNumA); ~SysFontInfo(); GBool match(SysFontInfo *fi); GBool match(GString *nameA, GBool boldA, GBool italicA); }; SysFontInfo::SysFontInfo(GString *nameA, GBool boldA, GBool italicA, GString *pathA, SysFontType typeA, int fontNumA) { name = nameA; bold = boldA; italic = italicA; path = pathA; type = typeA; fontNum = fontNumA; } SysFontInfo::~SysFontInfo() { delete name; delete path; } GBool SysFontInfo::match(SysFontInfo *fi) { return !strcasecmp(name->getCString(), fi->name->getCString()) && bold == fi->bold && italic == fi->italic; } GBool SysFontInfo::match(GString *nameA, GBool boldA, GBool italicA) { return !strcasecmp(name->getCString(), nameA->getCString()) && bold == boldA && italic == italicA; } //------------------------------------------------------------------------ // SysFontList //------------------------------------------------------------------------ class SysFontList { public: SysFontList(); ~SysFontList(); SysFontInfo *find(GString *name); #ifdef WIN32 void scanWindowsFonts(char *winFontDir); #endif private: #ifdef WIN32 SysFontInfo *makeWindowsFont(char *name, int fontNum, char *path); #endif GList *fonts; // [SysFontInfo] }; SysFontList::SysFontList() { fonts = new GList(); } SysFontList::~SysFontList() { deleteGList(fonts, SysFontInfo); } SysFontInfo *SysFontList::find(GString *name) { GString *name2; GBool bold, italic; SysFontInfo *fi; char c; int n, i; name2 = name->copy(); // remove space, comma, dash chars i = 0; while (i < name2->getLength()) { c = name2->getChar(i); if (c == ' ' || c == ',' || c == '-') { name2->del(i); } else { ++i; } } n = name2->getLength(); // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.) if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) { name2->del(n - 2, 2); n -= 2; } // look for "Regular" if (n > 7 && !strcmp(name2->getCString() + n - 7, "Regular")) { name2->del(n - 7, 7); n -= 7; } // look for "Italic" if (n > 6 && !strcmp(name2->getCString() + n - 6, "Italic")) { name2->del(n - 6, 6); italic = gTrue; n -= 6; } else { italic = gFalse; } // look for "Bold" if (n > 4 && !strcmp(name2->getCString() + n - 4, "Bold")) { name2->del(n - 4, 4); bold = gTrue; n -= 4; } else { bold = gFalse; } // remove trailing "MT" (FooMT-Bold, etc.) if (n > 2 && !strcmp(name2->getCString() + n - 2, "MT")) { name2->del(n - 2, 2); n -= 2; } // remove trailing "PS" if (n > 2 && !strcmp(name2->getCString() + n - 2, "PS")) { name2->del(n - 2, 2); n -= 2; } // remove trailing "IdentityH" if (n > 9 && !strcmp(name2->getCString() + n - 9, "IdentityH")) { name2->del(n - 9, 9); n -= 9; } // search for the font fi = NULL; for (i = 0; i < fonts->getLength(); ++i) { fi = (SysFontInfo *)fonts->get(i); if (fi->match(name2, bold, italic)) { break; } fi = NULL; } if (!fi && bold) { // try ignoring the bold flag for (i = 0; i < fonts->getLength(); ++i) { fi = (SysFontInfo *)fonts->get(i); if (fi->match(name2, gFalse, italic)) { break; } fi = NULL; } } if (!fi && (bold || italic)) { // try ignoring the bold and italic flags for (i = 0; i < fonts->getLength(); ++i) { fi = (SysFontInfo *)fonts->get(i); if (fi->match(name2, gFalse, gFalse)) { break; } fi = NULL; } } delete name2; return fi; } #ifdef WIN32 void SysFontList::scanWindowsFonts(char *winFontDir) { OSVERSIONINFO version; char *path; DWORD idx, valNameLen, dataLen, type; HKEY regKey; char valName[1024], data[1024]; int n, fontNum; char *p0, *p1; GString *fontPath; version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { path = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts\\"; } else { path = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts\\"; } if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, path, 0, KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, ®Key) == ERROR_SUCCESS) { idx = 0; while (1) { valNameLen = sizeof(valName) - 1; dataLen = sizeof(data) - 1; if (RegEnumValue(regKey, idx, valName, &valNameLen, NULL, &type, (LPBYTE)data, &dataLen) != ERROR_SUCCESS) { break; } if (type == REG_SZ && valNameLen > 0 && valNameLen < sizeof(valName) && dataLen > 0 && dataLen < sizeof(data)) { valName[valNameLen] = '\0'; data[dataLen] = '\0'; n = strlen(data); if (!strcasecmp(data + n - 4, ".ttf") || !strcasecmp(data + n - 4, ".ttc")) { fontPath = new GString(data); if (!(dataLen >= 3 && data[1] == ':' && data[2] == '\\')) { fontPath->insert(0, '\\'); fontPath->insert(0, winFontDir); } p0 = valName; fontNum = 0; while (*p0) { p1 = strstr(p0, " & "); if (p1) { *p1 = '\0'; p1 = p1 + 3; } else { p1 = p0 + strlen(p0); } fonts->append(makeWindowsFont(p0, fontNum, fontPath->getCString())); p0 = p1; ++fontNum; } delete fontPath; } } ++idx; } RegCloseKey(regKey); } } SysFontInfo *SysFontList::makeWindowsFont(char *name, int fontNum, char *path) { int n; GBool bold, italic; GString *s; char c; int i; SysFontType type; n = strlen(name); bold = italic = gFalse; // remove trailing ' (TrueType)' if (n > 11 && !strncmp(name + n - 11, " (TrueType)", 11)) { n -= 11; } // remove trailing ' Italic' if (n > 7 && !strncmp(name + n - 7, " Italic", 7)) { n -= 7; italic = gTrue; } // remove trailing ' Bold' if (n > 5 && !strncmp(name + n - 5, " Bold", 5)) { n -= 5; bold = gTrue; } // remove trailing ' Regular' if (n > 5 && !strncmp(name + n - 8, " Regular", 8)) { n -= 8; } //----- normalize the font name s = new GString(name, n); i = 0; while (i < s->getLength()) { c = s->getChar(i); if (c == ' ' || c == ',' || c == '-') { s->del(i); } else { ++i; } } if (!strcasecmp(path + strlen(path) - 4, ".ttc")) { type = sysFontTTC; } else { type = sysFontTTF; } return new SysFontInfo(s, bold, italic, new GString(path), type, fontNum); } #endif //------------------------------------------------------------------------ // KeyBinding //------------------------------------------------------------------------ KeyBinding::KeyBinding(int codeA, int modsA, int contextA, const char *cmd0) { code = codeA; mods = modsA; context = contextA; cmds = new GList(); cmds->append(new GString(cmd0)); } KeyBinding::KeyBinding(int codeA, int modsA, int contextA, const char *cmd0, const char *cmd1) { code = codeA; mods = modsA; context = contextA; cmds = new GList(); cmds->append(new GString(cmd0)); cmds->append(new GString(cmd1)); } KeyBinding::KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA) { code = codeA; mods = modsA; context = contextA; cmds = cmdsA; } KeyBinding::~KeyBinding() { deleteGList(cmds, GString); } #ifdef ENABLE_PLUGINS //------------------------------------------------------------------------ // Plugin //------------------------------------------------------------------------ class Plugin { public: static Plugin *load(char *type, char *name); ~Plugin(); private: #ifdef WIN32 Plugin(HMODULE libA); HMODULE lib; #else Plugin(void *dlA); void *dl; #endif }; Plugin *Plugin::load(char *type, char *name) { GString *path; Plugin *plugin; XpdfPluginVecTable *vt; XpdfBool (*xpdfInitPlugin)(void); #ifdef WIN32 HMODULE libA; #else void *dlA; #endif path = globalParams->getBaseDir(); appendToPath(path, "plugins"); appendToPath(path, type); appendToPath(path, name); #ifdef WIN32 path->append(".dll"); if (!(libA = LoadLibrary(path->getCString()))) { error(errIO, -1, "Failed to load plugin '{0:t}'", path); goto err1; } if (!(vt = (XpdfPluginVecTable *) GetProcAddress(libA, "xpdfPluginVecTable"))) { error(errIO, -1, "Failed to find xpdfPluginVecTable in plugin '{0:t}'", path); goto err2; } #else //~ need to deal with other extensions here path->append(".so"); if (!(dlA = dlopen(path->getCString(), RTLD_NOW))) { error(errIO, -1, "Failed to load plugin '{0:t}': {1:s}", path, dlerror()); goto err1; } if (!(vt = (XpdfPluginVecTable *)dlsym(dlA, "xpdfPluginVecTable"))) { error(errIO, -1, "Failed to find xpdfPluginVecTable in plugin '{0:t}'", path); goto err2; } #endif if (vt->version != xpdfPluginVecTable.version) { error(errIO, -1, "Plugin '{0:t}' is wrong version", path); goto err2; } memcpy(vt, &xpdfPluginVecTable, sizeof(xpdfPluginVecTable)); #ifdef WIN32 if (!(xpdfInitPlugin = (XpdfBool (*)(void)) GetProcAddress(libA, "xpdfInitPlugin"))) { error(errIO, -1, "Failed to find xpdfInitPlugin in plugin '{0:t}'", path); goto err2; } #else if (!(xpdfInitPlugin = (XpdfBool (*)(void))dlsym(dlA, "xpdfInitPlugin"))) { error(errIO, -1, "Failed to find xpdfInitPlugin in plugin '{0:t}'", path); goto err2; } #endif if (!(*xpdfInitPlugin)()) { error(errIO, -1, "Initialization of plugin '{0:t}' failed", path); goto err2; } #ifdef WIN32 plugin = new Plugin(libA); #else plugin = new Plugin(dlA); #endif delete path; return plugin; err2: #ifdef WIN32 FreeLibrary(libA); #else dlclose(dlA); #endif err1: delete path; return NULL; } #ifdef WIN32 Plugin::Plugin(HMODULE libA) { lib = libA; } #else Plugin::Plugin(void *dlA) { dl = dlA; } #endif Plugin::~Plugin() { void (*xpdfFreePlugin)(void); #ifdef WIN32 if ((xpdfFreePlugin = (void (*)(void)) GetProcAddress(lib, "xpdfFreePlugin"))) { (*xpdfFreePlugin)(); } FreeLibrary(lib); #else if ((xpdfFreePlugin = (void (*)(void))dlsym(dl, "xpdfFreePlugin"))) { (*xpdfFreePlugin)(); } dlclose(dl); #endif } #endif // ENABLE_PLUGINS //------------------------------------------------------------------------ // parsing //------------------------------------------------------------------------ GlobalParams::GlobalParams(char *cfgFileName) { UnicodeMap *map; GString *fileName; FILE *f; int i; #if MULTITHREADED gInitMutex(&mutex); gInitMutex(&unicodeMapCacheMutex); gInitMutex(&cMapCacheMutex); #endif initBuiltinFontTables(); // scan the encoding in reverse because we want the lowest-numbered // index for each char name ('space' is encoded twice) macRomanReverseMap = new NameToCharCode(); for (i = 255; i >= 0; --i) { if (macRomanEncoding[i]) { macRomanReverseMap->add(macRomanEncoding[i], (CharCode)i); } } #ifdef WIN32 // baseDir will be set by a call to setBaseDir baseDir = new GString(); #else baseDir = appendToPath(getHomeDir(), ".xpdf"); #endif nameToUnicode = new NameToCharCode(); cidToUnicodes = new GHash(gTrue); unicodeToUnicodes = new GHash(gTrue); residentUnicodeMaps = new GHash(); unicodeMaps = new GHash(gTrue); cMapDirs = new GHash(gTrue); toUnicodeDirs = new GList(); fontFiles = new GHash(gTrue); fontDirs = new GList(); ccFontFiles = new GHash(gTrue); sysFonts = new SysFontList(); #if HAVE_PAPER_H char *paperName; const struct paper *paperType; paperinit(); if ((paperName = systempapername())) { paperType = paperinfo(paperName); psPaperWidth = (int)paperpswidth(paperType); psPaperHeight = (int)paperpsheight(paperType); } else { error(errConfig, -1, "No paper information available - using defaults"); psPaperWidth = defPaperWidth; psPaperHeight = defPaperHeight; } paperdone(); #else psPaperWidth = defPaperWidth; psPaperHeight = defPaperHeight; #endif psImageableLLX = psImageableLLY = 0; psImageableURX = psPaperWidth; psImageableURY = psPaperHeight; psCrop = gTrue; psExpandSmaller = gFalse; psShrinkLarger = gTrue; psCenter = gTrue; psDuplex = gFalse; psLevel = psLevel2; psFile = NULL; psResidentFonts = new GHash(gTrue); psResidentFonts16 = new GList(); psResidentFontsCC = new GList(); psEmbedType1 = gTrue; psEmbedTrueType = gTrue; psEmbedCIDPostScript = gTrue; psEmbedCIDTrueType = gTrue; psFontPassthrough = gFalse; psPreload = gFalse; psOPI = gFalse; psASCIIHex = gFalse; psUncompressPreloadedImages = gFalse; psRasterResolution = 300; psRasterMono = gFalse; psAlwaysRasterize = gFalse; textEncoding = new GString("Latin1"); #if defined(WIN32) textEOL = eolDOS; #elif defined(MACOS) textEOL = eolMac; #else textEOL = eolUnix; #endif textPageBreaks = gTrue; textKeepTinyChars = gFalse; initialZoom = new GString("125"); continuousView = gFalse; enableT1lib = gTrue; enableFreeType = gTrue; disableFreeTypeHinting = gFalse; antialias = gTrue; vectorAntialias = gTrue; antialiasPrinting = gFalse; strokeAdjust = gTrue; screenType = screenUnset; screenSize = -1; screenDotRadius = -1; screenGamma = 1.0; screenBlackThreshold = 0.0; screenWhiteThreshold = 1.0; minLineWidth = 0.0; drawAnnotations = gTrue; overprintPreview = gFalse; launchCommand = NULL; urlCommand = NULL; movieCommand = NULL; mapNumericCharNames = gTrue; mapUnknownCharNames = gFalse; createDefaultKeyBindings(); printCommands = gFalse; errQuiet = gFalse; cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize); unicodeToUnicodeCache = new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize); unicodeMapCache = new UnicodeMapCache(); cMapCache = new CMapCache(); #ifdef ENABLE_PLUGINS plugins = new GList(); securityHandlers = new GList(); #endif // set up the initial nameToUnicode table for (i = 0; nameToUnicodeTab[i].name; ++i) { nameToUnicode->add(nameToUnicodeTab[i].name, nameToUnicodeTab[i].u); } // set up the residentUnicodeMaps table map = new UnicodeMap("Latin1", gFalse, latin1UnicodeMapRanges, latin1UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("ASCII7", gFalse, ascii7UnicodeMapRanges, ascii7UnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("Symbol", gFalse, symbolUnicodeMapRanges, symbolUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("ZapfDingbats", gFalse, zapfDingbatsUnicodeMapRanges, zapfDingbatsUnicodeMapLen); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("UTF-8", gTrue, &mapUTF8); residentUnicodeMaps->add(map->getEncodingName(), map); map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); residentUnicodeMaps->add(map->getEncodingName(), map); // look for a user config file, then a system-wide config file f = NULL; fileName = NULL; if (cfgFileName && cfgFileName[0]) { fileName = new GString(cfgFileName); if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; } } if (!f) { fileName = appendToPath(getHomeDir(), xpdfUserConfigFile); if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; } } if (!f) { #ifdef WIN32 char buf[512]; i = GetModuleFileName(NULL, buf, sizeof(buf)); if (i <= 0 || i >= sizeof(buf)) { // error or path too long for buffer - just use the current dir buf[0] = '\0'; } fileName = grabPath(buf); appendToPath(fileName, xpdfSysConfigFile); #else fileName = new GString(xpdfSysConfigFile); #endif if (!(f = fopen(fileName->getCString(), "r"))) { delete fileName; } } if (f) { parseFile(fileName, f); delete fileName; fclose(f); } } void GlobalParams::createDefaultKeyBindings() { keyBindings = new GList(); //----- mouse buttons keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress1, xpdfKeyModNone, xpdfKeyContextAny, "startSelection")); keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease1, xpdfKeyModNone, xpdfKeyContextAny, "endSelection", "followLinkNoSel")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress2, xpdfKeyModNone, xpdfKeyContextAny, "startPan")); keyBindings->append(new KeyBinding(xpdfKeyCodeMouseRelease2, xpdfKeyModNone, xpdfKeyContextAny, "endPan")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress3, xpdfKeyModNone, xpdfKeyContextAny, "postPopupMenu")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress4, xpdfKeyModNone, xpdfKeyContextAny, "scrollUpPrevPage(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress5, xpdfKeyModNone, xpdfKeyContextAny, "scrollDownNextPage(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress6, xpdfKeyModNone, xpdfKeyContextAny, "scrollLeft(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeMousePress7, xpdfKeyModNone, xpdfKeyContextAny, "scrollRight(16)")); //----- keys keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModCtrl, xpdfKeyContextAny, "gotoPage(1)")); keyBindings->append(new KeyBinding(xpdfKeyCodeHome, xpdfKeyModNone, xpdfKeyContextAny, "scrollToTopLeft")); keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModCtrl, xpdfKeyContextAny, "gotoLastPage")); keyBindings->append(new KeyBinding(xpdfKeyCodeEnd, xpdfKeyModNone, xpdfKeyContextAny, "scrollToBottomRight")); keyBindings->append(new KeyBinding(xpdfKeyCodePgUp, xpdfKeyModNone, xpdfKeyContextAny, "pageUp")); keyBindings->append(new KeyBinding(xpdfKeyCodeBackspace, xpdfKeyModNone, xpdfKeyContextAny, "pageUp")); keyBindings->append(new KeyBinding(xpdfKeyCodeDelete, xpdfKeyModNone, xpdfKeyContextAny, "pageUp")); keyBindings->append(new KeyBinding(xpdfKeyCodePgDn, xpdfKeyModNone, xpdfKeyContextAny, "pageDown")); keyBindings->append(new KeyBinding(' ', xpdfKeyModNone, xpdfKeyContextAny, "pageDown")); keyBindings->append(new KeyBinding(xpdfKeyCodeLeft, xpdfKeyModNone, xpdfKeyContextAny, "scrollLeft(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeRight, xpdfKeyModNone, xpdfKeyContextAny, "scrollRight(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeUp, xpdfKeyModNone, xpdfKeyContextAny, "scrollUp(16)")); keyBindings->append(new KeyBinding(xpdfKeyCodeDown, xpdfKeyModNone, xpdfKeyContextAny, "scrollDown(16)")); keyBindings->append(new KeyBinding('o', xpdfKeyModNone, xpdfKeyContextAny, "open")); keyBindings->append(new KeyBinding('O', xpdfKeyModNone, xpdfKeyContextAny, "open")); keyBindings->append(new KeyBinding('r', xpdfKeyModNone, xpdfKeyContextAny, "reload")); keyBindings->append(new KeyBinding('R', xpdfKeyModNone, xpdfKeyContextAny, "reload")); keyBindings->append(new KeyBinding('f', xpdfKeyModNone, xpdfKeyContextAny, "find")); keyBindings->append(new KeyBinding('F', xpdfKeyModNone, xpdfKeyContextAny, "find")); keyBindings->append(new KeyBinding('f', xpdfKeyModCtrl, xpdfKeyContextAny, "find")); keyBindings->append(new KeyBinding('g', xpdfKeyModCtrl, xpdfKeyContextAny, "findNext")); keyBindings->append(new KeyBinding('p', xpdfKeyModCtrl, xpdfKeyContextAny, "print")); keyBindings->append(new KeyBinding('n', xpdfKeyModNone, xpdfKeyContextScrLockOff, "nextPage")); keyBindings->append(new KeyBinding('N', xpdfKeyModNone, xpdfKeyContextScrLockOff, "nextPage")); keyBindings->append(new KeyBinding('n', xpdfKeyModNone, xpdfKeyContextScrLockOn, "nextPageNoScroll")); keyBindings->append(new KeyBinding('N', xpdfKeyModNone, xpdfKeyContextScrLockOn, "nextPageNoScroll")); keyBindings->append(new KeyBinding('p', xpdfKeyModNone, xpdfKeyContextScrLockOff, "prevPage")); keyBindings->append(new KeyBinding('P', xpdfKeyModNone, xpdfKeyContextScrLockOff, "prevPage")); keyBindings->append(new KeyBinding('p', xpdfKeyModNone, xpdfKeyContextScrLockOn, "prevPageNoScroll")); keyBindings->append(new KeyBinding('P', xpdfKeyModNone, xpdfKeyContextScrLockOn, "prevPageNoScroll")); keyBindings->append(new KeyBinding('v', xpdfKeyModNone, xpdfKeyContextAny, "goForward")); keyBindings->append(new KeyBinding('b', xpdfKeyModNone, xpdfKeyContextAny, "goBackward")); keyBindings->append(new KeyBinding('g', xpdfKeyModNone, xpdfKeyContextAny, "focusToPageNum")); keyBindings->append(new KeyBinding('0', xpdfKeyModNone, xpdfKeyContextAny, "zoomPercent(125)")); keyBindings->append(new KeyBinding('+', xpdfKeyModNone, xpdfKeyContextAny, "zoomIn")); keyBindings->append(new KeyBinding('-', xpdfKeyModNone, xpdfKeyContextAny, "zoomOut")); keyBindings->append(new KeyBinding('z', xpdfKeyModNone, xpdfKeyContextAny, "zoomFitPage")); keyBindings->append(new KeyBinding('w', xpdfKeyModNone, xpdfKeyContextAny, "zoomFitWidth")); keyBindings->append(new KeyBinding('f', xpdfKeyModAlt, xpdfKeyContextAny, "toggleFullScreenMode")); keyBindings->append(new KeyBinding('l', xpdfKeyModCtrl, xpdfKeyContextAny, "redraw")); keyBindings->append(new KeyBinding('w', xpdfKeyModCtrl, xpdfKeyContextAny, "closeWindow")); keyBindings->append(new KeyBinding('?', xpdfKeyModNone, xpdfKeyContextAny, "about")); keyBindings->append(new KeyBinding('q', xpdfKeyModNone, xpdfKeyContextAny, "quit")); keyBindings->append(new KeyBinding('Q', xpdfKeyModNone, xpdfKeyContextAny, "quit")); } void GlobalParams::parseFile(GString *fileName, FILE *f) { int line; char buf[512]; line = 1; while (getLine(buf, sizeof(buf) - 1, f)) { parseLine(buf, fileName, line); ++line; } } void GlobalParams::parseLine(char *buf, GString *fileName, int line) { GList *tokens; GString *cmd, *incFile; char *p1, *p2; FILE *f2; // break the line into tokens tokens = new GList(); p1 = buf; while (*p1) { for (; *p1 && isspace(*p1); ++p1) ; if (!*p1) { break; } if (*p1 == '"' || *p1 == '\'') { for (p2 = p1 + 1; *p2 && *p2 != *p1; ++p2) ; ++p1; } else { for (p2 = p1 + 1; *p2 && !isspace(*p2); ++p2) ; } tokens->append(new GString(p1, (int)(p2 - p1))); p1 = *p2 ? p2 + 1 : p2; } // parse the line if (tokens->getLength() > 0 && ((GString *)tokens->get(0))->getChar(0) != '#') { cmd = (GString *)tokens->get(0); if (!cmd->cmp("include")) { if (tokens->getLength() == 2) { incFile = (GString *)tokens->get(1); if ((f2 = openFile(incFile->getCString(), "r"))) { parseFile(incFile, f2); fclose(f2); } else { error(errConfig, -1, "Couldn't find included config file: '{0:t}' ({1:t}:{2:d})", incFile, fileName, line); } } else { error(errConfig, -1, "Bad 'include' config file command ({0:t}:{1:d})", fileName, line); } } else if (!cmd->cmp("nameToUnicode")) { parseNameToUnicode(tokens, fileName, line); } else if (!cmd->cmp("cidToUnicode")) { parseCIDToUnicode(tokens, fileName, line); } else if (!cmd->cmp("unicodeToUnicode")) { parseUnicodeToUnicode(tokens, fileName, line); } else if (!cmd->cmp("unicodeMap")) { parseUnicodeMap(tokens, fileName, line); } else if (!cmd->cmp("cMapDir")) { parseCMapDir(tokens, fileName, line); } else if (!cmd->cmp("toUnicodeDir")) { parseToUnicodeDir(tokens, fileName, line); } else if (!cmd->cmp("fontFile")) { parseFontFile(tokens, fileName, line); } else if (!cmd->cmp("fontDir")) { parseFontDir(tokens, fileName, line); } else if (!cmd->cmp("fontFileCC")) { parseFontFileCC(tokens, fileName, line); } else if (!cmd->cmp("psFile")) { parsePSFile(tokens, fileName, line); } else if (!cmd->cmp("psPaperSize")) { parsePSPaperSize(tokens, fileName, line); } else if (!cmd->cmp("psImageableArea")) { parsePSImageableArea(tokens, fileName, line); } else if (!cmd->cmp("psCrop")) { parseYesNo("psCrop", &psCrop, tokens, fileName, line); } else if (!cmd->cmp("psExpandSmaller")) { parseYesNo("psExpandSmaller", &psExpandSmaller, tokens, fileName, line); } else if (!cmd->cmp("psShrinkLarger")) { parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); } else if (!cmd->cmp("psCenter")) { parseYesNo("psCenter", &psCenter, tokens, fileName, line); } else if (!cmd->cmp("psDuplex")) { parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); } else if (!cmd->cmp("psLevel")) { parsePSLevel(tokens, fileName, line); } else if (!cmd->cmp("psResidentFont")) { parsePSResidentFont(tokens, fileName, line); } else if (!cmd->cmp("psResidentFont16")) { parsePSResidentFont16(tokens, fileName, line); } else if (!cmd->cmp("psResidentFontCC")) { parsePSResidentFontCC(tokens, fileName, line); } else if (!cmd->cmp("psEmbedType1Fonts")) { parseYesNo("psEmbedType1", &psEmbedType1, tokens, fileName, line); } else if (!cmd->cmp("psEmbedTrueTypeFonts")) { parseYesNo("psEmbedTrueType", &psEmbedTrueType, tokens, fileName, line); } else if (!cmd->cmp("psEmbedCIDPostScriptFonts")) { parseYesNo("psEmbedCIDPostScript", &psEmbedCIDPostScript, tokens, fileName, line); } else if (!cmd->cmp("psEmbedCIDTrueTypeFonts")) { parseYesNo("psEmbedCIDTrueType", &psEmbedCIDTrueType, tokens, fileName, line); } else if (!cmd->cmp("psFontPassthrough")) { parseYesNo("psFontPassthrough", &psFontPassthrough, tokens, fileName, line); } else if (!cmd->cmp("psPreload")) { parseYesNo("psPreload", &psPreload, tokens, fileName, line); } else if (!cmd->cmp("psOPI")) { parseYesNo("psOPI", &psOPI, tokens, fileName, line); } else if (!cmd->cmp("psASCIIHex")) { parseYesNo("psASCIIHex", &psASCIIHex, tokens, fileName, line); } else if (!cmd->cmp("psUncompressPreloadedImages")) { parseYesNo("psUncompressPreloadedImages", &psUncompressPreloadedImages, tokens, fileName, line); } else if (!cmd->cmp("psRasterResolution")) { parseFloat("psRasterResolution", &psRasterResolution, tokens, fileName, line); } else if (!cmd->cmp("psRasterMono")) { parseYesNo("psRasterMono", &psRasterMono, tokens, fileName, line); } else if (!cmd->cmp("psAlwaysRasterize")) { parseYesNo("psAlwaysRasterize", &psAlwaysRasterize, tokens, fileName, line); } else if (!cmd->cmp("textEncoding")) { parseTextEncoding(tokens, fileName, line); } else if (!cmd->cmp("textEOL")) { parseTextEOL(tokens, fileName, line); } else if (!cmd->cmp("textPageBreaks")) { parseYesNo("textPageBreaks", &textPageBreaks, tokens, fileName, line); } else if (!cmd->cmp("textKeepTinyChars")) { parseYesNo("textKeepTinyChars", &textKeepTinyChars, tokens, fileName, line); } else if (!cmd->cmp("initialZoom")) { parseInitialZoom(tokens, fileName, line); } else if (!cmd->cmp("continuousView")) { parseYesNo("continuousView", &continuousView, tokens, fileName, line); } else if (!cmd->cmp("enableT1lib")) { parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); } else if (!cmd->cmp("enableFreeType")) { parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); } else if (!cmd->cmp("disableFreeTypeHinting")) { parseYesNo("disableFreeTypeHinting", &disableFreeTypeHinting, tokens, fileName, line); } else if (!cmd->cmp("antialias")) { parseYesNo("antialias", &antialias, tokens, fileName, line); } else if (!cmd->cmp("vectorAntialias")) { parseYesNo("vectorAntialias", &vectorAntialias, tokens, fileName, line); } else if (!cmd->cmp("antialiasPrinting")) { parseYesNo("antialiasPrinting", &antialiasPrinting, tokens, fileName, line); } else if (!cmd->cmp("strokeAdjust")) { parseYesNo("strokeAdjust", &strokeAdjust, tokens, fileName, line); } else if (!cmd->cmp("screenType")) { parseScreenType(tokens, fileName, line); } else if (!cmd->cmp("screenSize")) { parseInteger("screenSize", &screenSize, tokens, fileName, line); } else if (!cmd->cmp("screenDotRadius")) { parseInteger("screenDotRadius", &screenDotRadius, tokens, fileName, line); } else if (!cmd->cmp("screenGamma")) { parseFloat("screenGamma", &screenGamma, tokens, fileName, line); } else if (!cmd->cmp("screenBlackThreshold")) { parseFloat("screenBlackThreshold", &screenBlackThreshold, tokens, fileName, line); } else if (!cmd->cmp("screenWhiteThreshold")) { parseFloat("screenWhiteThreshold", &screenWhiteThreshold, tokens, fileName, line); } else if (!cmd->cmp("minLineWidth")) { parseFloat("minLineWidth", &minLineWidth, tokens, fileName, line); } else if (!cmd->cmp("drawAnnotations")) { parseYesNo("drawAnnotations", &drawAnnotations, tokens, fileName, line); } else if (!cmd->cmp("overprintPreview")) { parseYesNo("overprintPreview", &overprintPreview, tokens, fileName, line); } else if (!cmd->cmp("launchCommand")) { parseCommand("launchCommand", &launchCommand, tokens, fileName, line); } else if (!cmd->cmp("urlCommand")) { parseCommand("urlCommand", &urlCommand, tokens, fileName, line); } else if (!cmd->cmp("movieCommand")) { parseCommand("movieCommand", &movieCommand, tokens, fileName, line); } else if (!cmd->cmp("mapNumericCharNames")) { parseYesNo("mapNumericCharNames", &mapNumericCharNames, tokens, fileName, line); } else if (!cmd->cmp("mapUnknownCharNames")) { parseYesNo("mapUnknownCharNames", &mapUnknownCharNames, tokens, fileName, line); } else if (!cmd->cmp("bind")) { parseBind(tokens, fileName, line); } else if (!cmd->cmp("unbind")) { parseUnbind(tokens, fileName, line); } else if (!cmd->cmp("printCommands")) { parseYesNo("printCommands", &printCommands, tokens, fileName, line); } else if (!cmd->cmp("errQuiet")) { parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); } else { error(errConfig, -1, "Unknown config file command '{0:t}' ({1:t}:{2:d})", cmd, fileName, line); if (!cmd->cmp("displayFontX") || !cmd->cmp("displayNamedCIDFontX") || !cmd->cmp("displayCIDFontX")) { error(errConfig, -1, "Xpdf no longer supports X fonts"); } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { error(errConfig, -1, "The t1libControl and freetypeControl options have been replaced by the enableT1lib, enableFreeType, and antialias options"); } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { error(errConfig, -1, "The config file format has changed since Xpdf 0.9x"); } } } deleteGList(tokens, GString); } void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, int line) { GString *name; char *tok1, *tok2; FILE *f; char buf[256]; int line2; Unicode u; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'nameToUnicode' config file command ({0:t}:{1:d})", fileName, line); return; } name = (GString *)tokens->get(1); if (!(f = openFile(name->getCString(), "r"))) { error(errConfig, -1, "Couldn't open 'nameToUnicode' file '{0:t}'", name); return; } line2 = 1; while (getLine(buf, sizeof(buf), f)) { tok1 = strtok(buf, " \t\r\n"); tok2 = strtok(NULL, " \t\r\n"); if (tok1 && tok2) { sscanf(tok1, "%x", &u); nameToUnicode->add(tok2, u); } else { error(errConfig, -1, "Bad line in 'nameToUnicode' file ({0:t}:{1:d})", name, line2); } ++line2; } fclose(f); } void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName, int line) { GString *collection, *name, *old; if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'cidToUnicode' config file command ({0:t}:{1:d})", fileName, line); return; } collection = (GString *)tokens->get(1); name = (GString *)tokens->get(2); if ((old = (GString *)cidToUnicodes->remove(collection))) { delete old; } cidToUnicodes->add(collection->copy(), name->copy()); } void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName, int line) { GString *font, *file, *old; if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'unicodeToUnicode' config file command ({0:t}:{1:d})", fileName, line); return; } font = (GString *)tokens->get(1); file = (GString *)tokens->get(2); if ((old = (GString *)unicodeToUnicodes->remove(font))) { delete old; } unicodeToUnicodes->add(font->copy(), file->copy()); } void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName, int line) { GString *encodingName, *name, *old; if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'unicodeMap' config file command ({0:t}:{1:d})", fileName, line); return; } encodingName = (GString *)tokens->get(1); name = (GString *)tokens->get(2); if ((old = (GString *)unicodeMaps->remove(encodingName))) { delete old; } unicodeMaps->add(encodingName->copy(), name->copy()); } void GlobalParams::parseCMapDir(GList *tokens, GString *fileName, int line) { GString *collection, *dir; GList *list; if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'cMapDir' config file command ({0:t}:{1:d})", fileName, line); return; } collection = (GString *)tokens->get(1); dir = (GString *)tokens->get(2); if (!(list = (GList *)cMapDirs->lookup(collection))) { list = new GList(); cMapDirs->add(collection->copy(), list); } list->append(dir->copy()); } void GlobalParams::parseToUnicodeDir(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'toUnicodeDir' config file command ({0:t}:{1:d})", fileName, line); return; } toUnicodeDirs->append(((GString *)tokens->get(1))->copy()); } void GlobalParams::parseFontFile(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'fontFile' config file command ({0:t}:{1:d})", fileName, line); return; } fontFiles->add(((GString *)tokens->get(1))->copy(), ((GString *)tokens->get(2))->copy()); } void GlobalParams::parseFontDir(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'fontDir' config file command ({0:t}:{1:d})", fileName, line); return; } fontDirs->append(((GString *)tokens->get(1))->copy()); } void GlobalParams::parseFontFileCC(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'fontFileCC' config file command ({0:t}:{1:d})", fileName, line); return; } ccFontFiles->add(((GString *)tokens->get(1))->copy(), ((GString *)tokens->get(2))->copy()); } void GlobalParams::parsePSFile(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'psFile' config file command ({0:t}:{1:d})", fileName, line); return; } if (psFile) { delete psFile; } psFile = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() == 2) { tok = (GString *)tokens->get(1); if (!setPSPaperSize(tok->getCString())) { error(errConfig, -1, "Bad 'psPaperSize' config file command ({0:s}:{1:d})", fileName, line); } } else if (tokens->getLength() == 3) { tok = (GString *)tokens->get(1); psPaperWidth = atoi(tok->getCString()); tok = (GString *)tokens->get(2); psPaperHeight = atoi(tok->getCString()); psImageableLLX = psImageableLLY = 0; psImageableURX = psPaperWidth; psImageableURY = psPaperHeight; } else { error(errConfig, -1, "Bad 'psPaperSize' config file command ({0:t}:{1:d})", fileName, line); } } void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 5) { error(errConfig, -1, "Bad 'psImageableArea' config file command ({0:t}:{1:d})", fileName, line); return; } psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); } void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'psLevel' config file command ({0:t}:{1:d})", fileName, line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("level1")) { psLevel = psLevel1; } else if (!tok->cmp("level1sep")) { psLevel = psLevel1Sep; } else if (!tok->cmp("level2")) { psLevel = psLevel2; } else if (!tok->cmp("level2sep")) { psLevel = psLevel2Sep; } else if (!tok->cmp("level3")) { psLevel = psLevel3; } else if (!tok->cmp("level3Sep")) { psLevel = psLevel3Sep; } else { error(errConfig, -1, "Bad 'psLevel' config file command ({0:t}:{1:d})", fileName, line); } } void GlobalParams::parsePSResidentFont(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'psResidentFont' config file command ({0:t}:{1:d})", fileName, line); return; } psResidentFonts->add(((GString *)tokens->get(1))->copy(), ((GString *)tokens->get(2))->copy()); } void GlobalParams::parsePSResidentFont16(GList *tokens, GString *fileName, int line) { PSFontParam16 *param; int wMode; GString *tok; if (tokens->getLength() != 5) { error(errConfig, -1, "Bad 'psResidentFont16' config file command ({0:t}:{1:d})", fileName, line); return; } tok = (GString *)tokens->get(2); if (!tok->cmp("H")) { wMode = 0; } else if (!tok->cmp("V")) { wMode = 1; } else { error(errConfig, -1, "Bad wMode in psResidentFont16 config file command ({1:t}:{2:d})", fileName, line); return; } param = new PSFontParam16(((GString *)tokens->get(1))->copy(), wMode, ((GString *)tokens->get(3))->copy(), ((GString *)tokens->get(4))->copy()); psResidentFonts16->append(param); } void GlobalParams::parsePSResidentFontCC(GList *tokens, GString *fileName, int line) { PSFontParam16 *param; int wMode; GString *tok; if (tokens->getLength() != 5) { error(errConfig, -1, "Bad 'psResidentFontCC' config file command ({0:t}:{1:d})", fileName, line); return; } tok = (GString *)tokens->get(2); if (!tok->cmp("H")) { wMode = 0; } else if (!tok->cmp("V")) { wMode = 1; } else { error(errConfig, -1, "Bad wMode in psResidentFontCC config file command ({1:t}:{2:d})", fileName, line); return; } param = new PSFontParam16(((GString *)tokens->get(1))->copy(), wMode, ((GString *)tokens->get(3))->copy(), ((GString *)tokens->get(4))->copy()); psResidentFontsCC->append(param); } void GlobalParams::parseTextEncoding(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'textEncoding' config file command ({0:s}:{1:d})", fileName, line); return; } delete textEncoding; textEncoding = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseTextEOL(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'textEOL' config file command ({0:t}:{1:d})", fileName, line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("unix")) { textEOL = eolUnix; } else if (!tok->cmp("dos")) { textEOL = eolDOS; } else if (!tok->cmp("mac")) { textEOL = eolMac; } else { error(errConfig, -1, "Bad 'textEOL' config file command ({0:t}:{1:d})", fileName, line); } } void GlobalParams::parseInitialZoom(GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'initialZoom' config file command ({0:t}:{1:d})", fileName, line); return; } delete initialZoom; initialZoom = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseScreenType(GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad 'screenType' config file command ({0:t}:{1:d})", fileName, line); return; } tok = (GString *)tokens->get(1); if (!tok->cmp("dispersed")) { screenType = screenDispersed; } else if (!tok->cmp("clustered")) { screenType = screenClustered; } else if (!tok->cmp("stochasticClustered")) { screenType = screenStochasticClustered; } else { error(errConfig, -1, "Bad 'screenType' config file command ({0:t}:{1:d})", fileName, line); } } void GlobalParams::parseBind(GList *tokens, GString *fileName, int line) { KeyBinding *binding; GList *cmds; int code, mods, context, i; if (tokens->getLength() < 4) { error(errConfig, -1, "Bad 'bind' config file command ({0:t}:{1:d})", fileName, line); return; } if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2), &code, &mods, &context, "bind", tokens, fileName, line)) { return; } for (i = 0; i < keyBindings->getLength(); ++i) { binding = (KeyBinding *)keyBindings->get(i); if (binding->code == code && binding->mods == mods && binding->context == context) { delete (KeyBinding *)keyBindings->del(i); break; } } cmds = new GList(); for (i = 3; i < tokens->getLength(); ++i) { cmds->append(((GString *)tokens->get(i))->copy()); } keyBindings->append(new KeyBinding(code, mods, context, cmds)); } void GlobalParams::parseUnbind(GList *tokens, GString *fileName, int line) { KeyBinding *binding; int code, mods, context, i; if (tokens->getLength() != 3) { error(errConfig, -1, "Bad 'unbind' config file command ({0:t}:{1:d})", fileName, line); return; } if (!parseKey((GString *)tokens->get(1), (GString *)tokens->get(2), &code, &mods, &context, "unbind", tokens, fileName, line)) { return; } for (i = 0; i < keyBindings->getLength(); ++i) { binding = (KeyBinding *)keyBindings->get(i); if (binding->code == code && binding->mods == mods && binding->context == context) { delete (KeyBinding *)keyBindings->del(i); break; } } } GBool GlobalParams::parseKey(GString *modKeyStr, GString *contextStr, int *code, int *mods, int *context, const char *cmdName, GList *tokens, GString *fileName, int line) { char *p0; int btn; *mods = xpdfKeyModNone; p0 = modKeyStr->getCString(); while (1) { if (!strncmp(p0, "shift-", 6)) { *mods |= xpdfKeyModShift; p0 += 6; } else if (!strncmp(p0, "ctrl-", 5)) { *mods |= xpdfKeyModCtrl; p0 += 5; } else if (!strncmp(p0, "alt-", 4)) { *mods |= xpdfKeyModAlt; p0 += 4; } else { break; } } if (!strcmp(p0, "space")) { *code = ' '; } else if (!strcmp(p0, "tab")) { *code = xpdfKeyCodeTab; } else if (!strcmp(p0, "return")) { *code = xpdfKeyCodeReturn; } else if (!strcmp(p0, "enter")) { *code = xpdfKeyCodeEnter; } else if (!strcmp(p0, "backspace")) { *code = xpdfKeyCodeBackspace; } else if (!strcmp(p0, "insert")) { *code = xpdfKeyCodeInsert; } else if (!strcmp(p0, "delete")) { *code = xpdfKeyCodeDelete; } else if (!strcmp(p0, "home")) { *code = xpdfKeyCodeHome; } else if (!strcmp(p0, "end")) { *code = xpdfKeyCodeEnd; } else if (!strcmp(p0, "pgup")) { *code = xpdfKeyCodePgUp; } else if (!strcmp(p0, "pgdn")) { *code = xpdfKeyCodePgDn; } else if (!strcmp(p0, "left")) { *code = xpdfKeyCodeLeft; } else if (!strcmp(p0, "right")) { *code = xpdfKeyCodeRight; } else if (!strcmp(p0, "up")) { *code = xpdfKeyCodeUp; } else if (!strcmp(p0, "down")) { *code = xpdfKeyCodeDown; } else if (p0[0] == 'f' && p0[1] >= '1' && p0[1] <= '9' && !p0[2]) { *code = xpdfKeyCodeF1 + (p0[1] - '1'); } else if (p0[0] == 'f' && ((p0[1] >= '1' && p0[1] <= '2' && p0[2] >= '0' && p0[2] <= '9') || (p0[1] == '3' && p0[2] >= '0' && p0[2] <= '5')) && !p0[3]) { *code = xpdfKeyCodeF1 + 10 * (p0[1] - '0') + (p0[2] - '0') - 1; } else if (!strncmp(p0, "mousePress", 10) && p0[10] >= '0' && p0[10] <= '9' && (!p0[11] || (p0[11] >= '0' && p0[11] <= '9' && !p0[12])) && (btn = atoi(p0 + 10)) >= 1 && btn <= 32) { *code = xpdfKeyCodeMousePress1 + btn - 1; } else if (!strncmp(p0, "mouseRelease", 12) && p0[12] >= '0' && p0[12] <= '9' && (!p0[13] || (p0[13] >= '0' && p0[13] <= '9' && !p0[14])) && (btn = atoi(p0 + 12)) >= 1 && btn <= 32) { *code = xpdfKeyCodeMouseRelease1 + btn - 1; } else if (*p0 >= 0x20 && *p0 <= 0x7e && !p0[1]) { *code = (int)*p0; } else { error(errConfig, -1, "Bad key/modifier in '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return gFalse; } p0 = contextStr->getCString(); if (!strcmp(p0, "any")) { *context = xpdfKeyContextAny; } else { *context = xpdfKeyContextAny; while (1) { if (!strncmp(p0, "fullScreen", 10)) { *context |= xpdfKeyContextFullScreen; p0 += 10; } else if (!strncmp(p0, "window", 6)) { *context |= xpdfKeyContextWindow; p0 += 6; } else if (!strncmp(p0, "continuous", 10)) { *context |= xpdfKeyContextContinuous; p0 += 10; } else if (!strncmp(p0, "singlePage", 10)) { *context |= xpdfKeyContextSinglePage; p0 += 10; } else if (!strncmp(p0, "overLink", 8)) { *context |= xpdfKeyContextOverLink; p0 += 8; } else if (!strncmp(p0, "offLink", 7)) { *context |= xpdfKeyContextOffLink; p0 += 7; } else if (!strncmp(p0, "outline", 7)) { *context |= xpdfKeyContextOutline; p0 += 7; } else if (!strncmp(p0, "mainWin", 7)) { *context |= xpdfKeyContextMainWin; p0 += 7; } else if (!strncmp(p0, "scrLockOn", 9)) { *context |= xpdfKeyContextScrLockOn; p0 += 9; } else if (!strncmp(p0, "scrLockOff", 10)) { *context |= xpdfKeyContextScrLockOff; p0 += 10; } else { error(errConfig, -1, "Bad context in '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return gFalse; } if (!*p0) { break; } if (*p0 != ',') { error(errConfig, -1, "Bad context in '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return gFalse; } ++p0; } } return gTrue; } void GlobalParams::parseCommand(const char *cmdName, GString **val, GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } if (*val) { delete *val; } *val = ((GString *)tokens->get(1))->copy(); } void GlobalParams::parseYesNo(const char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line) { GString *tok; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } tok = (GString *)tokens->get(1); if (!parseYesNo2(tok->getCString(), flag)) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); } } GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { if (!strcmp(token, "yes")) { *flag = gTrue; } else if (!strcmp(token, "no")) { *flag = gFalse; } else { return gFalse; } return gTrue; } void GlobalParams::parseInteger(const char *cmdName, int *val, GList *tokens, GString *fileName, int line) { GString *tok; int i; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } tok = (GString *)tokens->get(1); if (tok->getLength() == 0) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } if (tok->getChar(0) == '-') { i = 1; } else { i = 0; } for (; i < tok->getLength(); ++i) { if (tok->getChar(i) < '0' || tok->getChar(i) > '9') { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } } *val = atoi(tok->getCString()); } void GlobalParams::parseFloat(const char *cmdName, double *val, GList *tokens, GString *fileName, int line) { GString *tok; int i; if (tokens->getLength() != 2) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } tok = (GString *)tokens->get(1); if (tok->getLength() == 0) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } if (tok->getChar(0) == '-') { i = 1; } else { i = 0; } for (; i < tok->getLength(); ++i) { if (!((tok->getChar(i) >= '0' && tok->getChar(i) <= '9') || tok->getChar(i) == '.')) { error(errConfig, -1, "Bad '{0:s}' config file command ({1:t}:{2:d})", cmdName, fileName, line); return; } } *val = atof(tok->getCString()); } GlobalParams::~GlobalParams() { GHashIter *iter; GString *key; GList *list; freeBuiltinFontTables(); delete macRomanReverseMap; delete baseDir; delete nameToUnicode; deleteGHash(cidToUnicodes, GString); deleteGHash(unicodeToUnicodes, GString); deleteGHash(residentUnicodeMaps, UnicodeMap); deleteGHash(unicodeMaps, GString); deleteGList(toUnicodeDirs, GString); deleteGHash(fontFiles, GString); deleteGList(fontDirs, GString); deleteGHash(ccFontFiles, GString); delete sysFonts; if (psFile) { delete psFile; } deleteGHash(psResidentFonts, GString); deleteGList(psResidentFonts16, PSFontParam16); deleteGList(psResidentFontsCC, PSFontParam16); delete textEncoding; delete initialZoom; if (launchCommand) { delete launchCommand; } if (urlCommand) { delete urlCommand; } if (movieCommand) { delete movieCommand; } deleteGList(keyBindings, KeyBinding); cMapDirs->startIter(&iter); while (cMapDirs->getNext(&iter, &key, (void **)&list)) { deleteGList(list, GString); } delete cMapDirs; delete cidToUnicodeCache; delete unicodeToUnicodeCache; delete unicodeMapCache; delete cMapCache; #ifdef ENABLE_PLUGINS delete securityHandlers; deleteGList(plugins, Plugin); #endif #if MULTITHREADED gDestroyMutex(&mutex); gDestroyMutex(&unicodeMapCacheMutex); gDestroyMutex(&cMapCacheMutex); #endif } //------------------------------------------------------------------------ void GlobalParams::setBaseDir(char *dir) { delete baseDir; baseDir = new GString(dir); } void GlobalParams::setupBaseFonts(char *dir) { GString *fontName; GString *fileName; #ifdef WIN32 HMODULE shell32Lib; BOOL (__stdcall *SHGetSpecialFolderPathFunc)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate); char winFontDir[MAX_PATH]; #endif FILE *f; int i, j; #ifdef WIN32 // SHGetSpecialFolderPath isn't available in older versions of // shell32.dll (Win95 and WinNT4), so do a dynamic load winFontDir[0] = '\0'; if ((shell32Lib = LoadLibrary("shell32.dll"))) { if ((SHGetSpecialFolderPathFunc = (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate)) GetProcAddress(shell32Lib, "SHGetSpecialFolderPathA"))) { if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, CSIDL_FONTS, FALSE)) { winFontDir[0] = '\0'; } } } #endif for (i = 0; displayFontTab[i].name; ++i) { if (fontFiles->lookup(displayFontTab[i].name)) { continue; } fontName = new GString(displayFontTab[i].name); fileName = NULL; if (dir) { fileName = appendToPath(new GString(dir), displayFontTab[i].t1FileName); if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { delete fileName; fileName = NULL; } } #ifdef WIN32 if (!fileName && winFontDir[0] && displayFontTab[i].ttFileName) { fileName = appendToPath(new GString(winFontDir), displayFontTab[i].ttFileName); if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { delete fileName; fileName = NULL; } } // SHGetSpecialFolderPath(CSIDL_FONTS) doesn't work on Win 2k Server // or Win2003 Server, or with older versions of shell32.dll, so check // the "standard" directories if (displayFontTab[i].ttFileName) { for (j = 0; !fileName && displayFontDirs[j]; ++j) { fileName = appendToPath(new GString(displayFontDirs[j]), displayFontTab[i].ttFileName); if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { delete fileName; fileName = NULL; } } } #else // WIN32 for (j = 0; !fileName && displayFontDirs[j]; ++j) { fileName = appendToPath(new GString(displayFontDirs[j]), displayFontTab[i].t1FileName); if ((f = fopen(fileName->getCString(), "rb"))) { fclose(f); } else { delete fileName; fileName = NULL; } } #endif // WIN32 if (!fileName) { error(errConfig, -1, "No display font for '{0:s}'", displayFontTab[i].name); delete fontName; continue; } addFontFile(fontName, fileName); } #ifdef WIN32 if (winFontDir[0]) { sysFonts->scanWindowsFonts(winFontDir); } #endif } //------------------------------------------------------------------------ // accessors //------------------------------------------------------------------------ CharCode GlobalParams::getMacRomanCharCode(char *charName) { // no need to lock - macRomanReverseMap is constant return macRomanReverseMap->lookup(charName); } GString *GlobalParams::getBaseDir() { GString *s; lockGlobalParams; s = baseDir->copy(); unlockGlobalParams; return s; } Unicode GlobalParams::mapNameToUnicode(const char *charName) { // no need to lock - nameToUnicode is constant return nameToUnicode->lookup(charName); } UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) { UnicodeMap *map; lockGlobalParams; map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName); unlockGlobalParams; if (map) { map->incRefCnt(); } return map; } FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) { GString *fileName; FILE *f; lockGlobalParams; if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) { f = openFile(fileName->getCString(), "r"); } else { f = NULL; } unlockGlobalParams; return f; } FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) { GList *list; GString *dir; GString *fileName; FILE *f; int i; lockGlobalParams; if (!(list = (GList *)cMapDirs->lookup(collection))) { unlockGlobalParams; return NULL; } for (i = 0; i < list->getLength(); ++i) { dir = (GString *)list->get(i); fileName = appendToPath(dir->copy(), cMapName->getCString()); f = openFile(fileName->getCString(), "r"); delete fileName; if (f) { unlockGlobalParams; return f; } } unlockGlobalParams; return NULL; } FILE *GlobalParams::findToUnicodeFile(GString *name) { GString *dir, *fileName; FILE *f; int i; lockGlobalParams; for (i = 0; i < toUnicodeDirs->getLength(); ++i) { dir = (GString *)toUnicodeDirs->get(i); fileName = appendToPath(dir->copy(), name->getCString()); f = openFile(fileName->getCString(), "r"); delete fileName; if (f) { unlockGlobalParams; return f; } } unlockGlobalParams; return NULL; } GString *GlobalParams::findFontFile(GString *fontName) { static const char *exts[] = { ".pfa", ".pfb", ".ttf", ".ttc" }; GString *path, *dir; #ifdef WIN32 GString *fontNameU; #endif const char *ext; FILE *f; int i, j; lockGlobalParams; if ((path = (GString *)fontFiles->lookup(fontName))) { path = path->copy(); unlockGlobalParams; return path; } for (i = 0; i < fontDirs->getLength(); ++i) { dir = (GString *)fontDirs->get(i); for (j = 0; j < (int)(sizeof(exts) / sizeof(exts[0])); ++j) { ext = exts[j]; #ifdef WIN32 fontNameU = fileNameToUTF8(fontName->getCString()); path = appendToPath(dir->copy(), fontNameU->getCString()); delete fontNameU; #else path = appendToPath(dir->copy(), fontName->getCString()); #endif path->append(ext); if ((f = openFile(path->getCString(), "rb"))) { fclose(f); unlockGlobalParams; return path; } delete path; } } unlockGlobalParams; return NULL; } GString *GlobalParams::findSystemFontFile(GString *fontName, SysFontType *type, int *fontNum) { SysFontInfo *fi; GString *path; path = NULL; lockGlobalParams; if ((fi = sysFonts->find(fontName))) { path = fi->path->copy(); *type = fi->type; *fontNum = fi->fontNum; } unlockGlobalParams; return path; } GString *GlobalParams::findCCFontFile(GString *collection) { GString *path; lockGlobalParams; if ((path = (GString *)ccFontFiles->lookup(collection))) { path = path->copy(); } unlockGlobalParams; return path; } GString *GlobalParams::getPSFile() { GString *s; lockGlobalParams; s = psFile ? psFile->copy() : (GString *)NULL; unlockGlobalParams; return s; } int GlobalParams::getPSPaperWidth() { int w; lockGlobalParams; w = psPaperWidth; unlockGlobalParams; return w; } int GlobalParams::getPSPaperHeight() { int h; lockGlobalParams; h = psPaperHeight; unlockGlobalParams; return h; } void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { lockGlobalParams; *llx = psImageableLLX; *lly = psImageableLLY; *urx = psImageableURX; *ury = psImageableURY; unlockGlobalParams; } GBool GlobalParams::getPSCrop() { GBool f; lockGlobalParams; f = psCrop; unlockGlobalParams; return f; } GBool GlobalParams::getPSExpandSmaller() { GBool f; lockGlobalParams; f = psExpandSmaller; unlockGlobalParams; return f; } GBool GlobalParams::getPSShrinkLarger() { GBool f; lockGlobalParams; f = psShrinkLarger; unlockGlobalParams; return f; } GBool GlobalParams::getPSCenter() { GBool f; lockGlobalParams; f = psCenter; unlockGlobalParams; return f; } GBool GlobalParams::getPSDuplex() { GBool d; lockGlobalParams; d = psDuplex; unlockGlobalParams; return d; } PSLevel GlobalParams::getPSLevel() { PSLevel level; lockGlobalParams; level = psLevel; unlockGlobalParams; return level; } GString *GlobalParams::getPSResidentFont(GString *fontName) { GString *psName; lockGlobalParams; psName = (GString *)psResidentFonts->lookup(fontName); unlockGlobalParams; return psName; } GList *GlobalParams::getPSResidentFonts() { GList *names; GHashIter *iter; GString *name; GString *psName; names = new GList(); lockGlobalParams; psResidentFonts->startIter(&iter); while (psResidentFonts->getNext(&iter, &name, (void **)&psName)) { names->append(psName->copy()); } unlockGlobalParams; return names; } PSFontParam16 *GlobalParams::getPSResidentFont16(GString *fontName, int wMode) { PSFontParam16 *p; int i; lockGlobalParams; p = NULL; for (i = 0; i < psResidentFonts16->getLength(); ++i) { p = (PSFontParam16 *)psResidentFonts16->get(i); if (!(p->name->cmp(fontName)) && p->wMode == wMode) { break; } p = NULL; } unlockGlobalParams; return p; } PSFontParam16 *GlobalParams::getPSResidentFontCC(GString *collection, int wMode) { PSFontParam16 *p; int i; lockGlobalParams; p = NULL; for (i = 0; i < psResidentFontsCC->getLength(); ++i) { p = (PSFontParam16 *)psResidentFontsCC->get(i); if (!(p->name->cmp(collection)) && p->wMode == wMode) { break; } p = NULL; } unlockGlobalParams; return p; } GBool GlobalParams::getPSEmbedType1() { GBool e; lockGlobalParams; e = psEmbedType1; unlockGlobalParams; return e; } GBool GlobalParams::getPSEmbedTrueType() { GBool e; lockGlobalParams; e = psEmbedTrueType; unlockGlobalParams; return e; } GBool GlobalParams::getPSEmbedCIDPostScript() { GBool e; lockGlobalParams; e = psEmbedCIDPostScript; unlockGlobalParams; return e; } GBool GlobalParams::getPSEmbedCIDTrueType() { GBool e; lockGlobalParams; e = psEmbedCIDTrueType; unlockGlobalParams; return e; } GBool GlobalParams::getPSFontPassthrough() { GBool e; lockGlobalParams; e = psFontPassthrough; unlockGlobalParams; return e; } GBool GlobalParams::getPSPreload() { GBool preload; lockGlobalParams; preload = psPreload; unlockGlobalParams; return preload; } GBool GlobalParams::getPSOPI() { GBool opi; lockGlobalParams; opi = psOPI; unlockGlobalParams; return opi; } GBool GlobalParams::getPSASCIIHex() { GBool ah; lockGlobalParams; ah = psASCIIHex; unlockGlobalParams; return ah; } GBool GlobalParams::getPSUncompressPreloadedImages() { GBool ah; lockGlobalParams; ah = psUncompressPreloadedImages; unlockGlobalParams; return ah; } double GlobalParams::getPSRasterResolution() { double res; lockGlobalParams; res = psRasterResolution; unlockGlobalParams; return res; } GBool GlobalParams::getPSRasterMono() { GBool mono; lockGlobalParams; mono = psRasterMono; unlockGlobalParams; return mono; } GBool GlobalParams::getPSAlwaysRasterize() { GBool rast; lockGlobalParams; rast = psAlwaysRasterize; unlockGlobalParams; return rast; } GString *GlobalParams::getTextEncodingName() { GString *s; lockGlobalParams; s = textEncoding->copy(); unlockGlobalParams; return s; } EndOfLineKind GlobalParams::getTextEOL() { EndOfLineKind eol; lockGlobalParams; eol = textEOL; unlockGlobalParams; return eol; } GBool GlobalParams::getTextPageBreaks() { GBool pageBreaks; lockGlobalParams; pageBreaks = textPageBreaks; unlockGlobalParams; return pageBreaks; } GBool GlobalParams::getTextKeepTinyChars() { GBool tiny; lockGlobalParams; tiny = textKeepTinyChars; unlockGlobalParams; return tiny; } GString *GlobalParams::getInitialZoom() { GString *s; lockGlobalParams; s = initialZoom->copy(); unlockGlobalParams; return s; } GBool GlobalParams::getContinuousView() { GBool f; lockGlobalParams; f = continuousView; unlockGlobalParams; return f; } GBool GlobalParams::getEnableT1lib() { GBool f; lockGlobalParams; f = enableT1lib; unlockGlobalParams; return f; } GBool GlobalParams::getEnableFreeType() { GBool f; lockGlobalParams; f = enableFreeType; unlockGlobalParams; return f; } GBool GlobalParams::getDisableFreeTypeHinting() { GBool f; lockGlobalParams; f = disableFreeTypeHinting; unlockGlobalParams; return f; } GBool GlobalParams::getAntialias() { GBool f; lockGlobalParams; f = antialias; unlockGlobalParams; return f; } GBool GlobalParams::getVectorAntialias() { GBool f; lockGlobalParams; f = vectorAntialias; unlockGlobalParams; return f; } GBool GlobalParams::getAntialiasPrinting() { GBool f; lockGlobalParams; f = antialiasPrinting; unlockGlobalParams; return f; } GBool GlobalParams::getStrokeAdjust() { GBool f; lockGlobalParams; f = strokeAdjust; unlockGlobalParams; return f; } ScreenType GlobalParams::getScreenType() { ScreenType t; lockGlobalParams; t = screenType; unlockGlobalParams; return t; } int GlobalParams::getScreenSize() { int size; lockGlobalParams; size = screenSize; unlockGlobalParams; return size; } int GlobalParams::getScreenDotRadius() { int r; lockGlobalParams; r = screenDotRadius; unlockGlobalParams; return r; } double GlobalParams::getScreenGamma() { double gamma; lockGlobalParams; gamma = screenGamma; unlockGlobalParams; return gamma; } double GlobalParams::getScreenBlackThreshold() { double thresh; lockGlobalParams; thresh = screenBlackThreshold; unlockGlobalParams; return thresh; } double GlobalParams::getScreenWhiteThreshold() { double thresh; lockGlobalParams; thresh = screenWhiteThreshold; unlockGlobalParams; return thresh; } double GlobalParams::getMinLineWidth() { double w; lockGlobalParams; w = minLineWidth; unlockGlobalParams; return w; } GBool GlobalParams::getDrawAnnotations() { GBool draw; lockGlobalParams; draw = drawAnnotations; unlockGlobalParams; return draw; } GBool GlobalParams::getMapNumericCharNames() { GBool map; lockGlobalParams; map = mapNumericCharNames; unlockGlobalParams; return map; } GBool GlobalParams::getMapUnknownCharNames() { GBool map; lockGlobalParams; map = mapUnknownCharNames; unlockGlobalParams; return map; } GList *GlobalParams::getKeyBinding(int code, int mods, int context) { KeyBinding *binding; GList *cmds; int modMask; int i, j; lockGlobalParams; cmds = NULL; // for ASCII chars, ignore the shift modifier modMask = code <= 0xff ? ~xpdfKeyModShift : ~0; for (i = 0; i < keyBindings->getLength(); ++i) { binding = (KeyBinding *)keyBindings->get(i); if (binding->code == code && (binding->mods & modMask) == (mods & modMask) && (~binding->context | context) == ~0) { cmds = new GList(); for (j = 0; j < binding->cmds->getLength(); ++j) { cmds->append(((GString *)binding->cmds->get(j))->copy()); } break; } } unlockGlobalParams; return cmds; } GBool GlobalParams::getPrintCommands() { GBool p; lockGlobalParams; p = printCommands; unlockGlobalParams; return p; } GBool GlobalParams::getErrQuiet() { // no locking -- this function may get called from inside a locked // section return errQuiet; } CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { GString *fileName; CharCodeToUnicode *ctu; lockGlobalParams; if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) { if ((fileName = (GString *)cidToUnicodes->lookup(collection)) && (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) { cidToUnicodeCache->add(ctu); } } unlockGlobalParams; return ctu; } CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) { CharCodeToUnicode *ctu; GHashIter *iter; GString *fontPattern, *fileName; lockGlobalParams; fileName = NULL; unicodeToUnicodes->startIter(&iter); while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) { if (strstr(fontName->getCString(), fontPattern->getCString())) { unicodeToUnicodes->killIter(&iter); break; } fileName = NULL; } if (fileName) { if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) { if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) { unicodeToUnicodeCache->add(ctu); } } } else { ctu = NULL; } unlockGlobalParams; return ctu; } UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) { return getUnicodeMap2(encodingName); } UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) { UnicodeMap *map; if (!(map = getResidentUnicodeMap(encodingName))) { lockUnicodeMapCache; map = unicodeMapCache->getUnicodeMap(encodingName); unlockUnicodeMapCache; } return map; } CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) { CMap *cMap; lockCMapCache; cMap = cMapCache->getCMap(collection, cMapName); unlockCMapCache; return cMap; } UnicodeMap *GlobalParams::getTextEncoding() { return getUnicodeMap2(textEncoding); } //------------------------------------------------------------------------ // functions to set parameters //------------------------------------------------------------------------ void GlobalParams::addFontFile(GString *fontName, GString *path) { lockGlobalParams; fontFiles->add(fontName, path); unlockGlobalParams; } void GlobalParams::setPSFile(char *file) { lockGlobalParams; if (psFile) { delete psFile; } psFile = new GString(file); unlockGlobalParams; } GBool GlobalParams::setPSPaperSize(char *size) { lockGlobalParams; if (!strcmp(size, "match")) { psPaperWidth = psPaperHeight = -1; } else if (!strcmp(size, "letter")) { psPaperWidth = 612; psPaperHeight = 792; } else if (!strcmp(size, "legal")) { psPaperWidth = 612; psPaperHeight = 1008; } else if (!strcmp(size, "A4")) { psPaperWidth = 595; psPaperHeight = 842; } else if (!strcmp(size, "A3")) { psPaperWidth = 842; psPaperHeight = 1190; } else { unlockGlobalParams; return gFalse; } psImageableLLX = psImageableLLY = 0; psImageableURX = psPaperWidth; psImageableURY = psPaperHeight; unlockGlobalParams; return gTrue; } void GlobalParams::setPSPaperWidth(int width) { lockGlobalParams; psPaperWidth = width; psImageableLLX = 0; psImageableURX = psPaperWidth; unlockGlobalParams; } void GlobalParams::setPSPaperHeight(int height) { lockGlobalParams; psPaperHeight = height; psImageableLLY = 0; psImageableURY = psPaperHeight; unlockGlobalParams; } void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { lockGlobalParams; psImageableLLX = llx; psImageableLLY = lly; psImageableURX = urx; psImageableURY = ury; unlockGlobalParams; } void GlobalParams::setPSCrop(GBool crop) { lockGlobalParams; psCrop = crop; unlockGlobalParams; } void GlobalParams::setPSExpandSmaller(GBool expand) { lockGlobalParams; psExpandSmaller = expand; unlockGlobalParams; } void GlobalParams::setPSShrinkLarger(GBool shrink) { lockGlobalParams; psShrinkLarger = shrink; unlockGlobalParams; } void GlobalParams::setPSCenter(GBool center) { lockGlobalParams; psCenter = center; unlockGlobalParams; } void GlobalParams::setPSDuplex(GBool duplex) { lockGlobalParams; psDuplex = duplex; unlockGlobalParams; } void GlobalParams::setPSLevel(PSLevel level) { lockGlobalParams; psLevel = level; unlockGlobalParams; } void GlobalParams::setPSEmbedType1(GBool embed) { lockGlobalParams; psEmbedType1 = embed; unlockGlobalParams; } void GlobalParams::setPSEmbedTrueType(GBool embed) { lockGlobalParams; psEmbedTrueType = embed; unlockGlobalParams; } void GlobalParams::setPSEmbedCIDPostScript(GBool embed) { lockGlobalParams; psEmbedCIDPostScript = embed; unlockGlobalParams; } void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { lockGlobalParams; psEmbedCIDTrueType = embed; unlockGlobalParams; } void GlobalParams::setPSFontPassthrough(GBool passthrough) { lockGlobalParams; psFontPassthrough = passthrough; unlockGlobalParams; } void GlobalParams::setPSPreload(GBool preload) { lockGlobalParams; psPreload = preload; unlockGlobalParams; } void GlobalParams::setPSOPI(GBool opi) { lockGlobalParams; psOPI = opi; unlockGlobalParams; } void GlobalParams::setPSASCIIHex(GBool hex) { lockGlobalParams; psASCIIHex = hex; unlockGlobalParams; } void GlobalParams::setTextEncoding(char *encodingName) { lockGlobalParams; delete textEncoding; textEncoding = new GString(encodingName); unlockGlobalParams; } GBool GlobalParams::setTextEOL(char *s) { lockGlobalParams; if (!strcmp(s, "unix")) { textEOL = eolUnix; } else if (!strcmp(s, "dos")) { textEOL = eolDOS; } else if (!strcmp(s, "mac")) { textEOL = eolMac; } else { unlockGlobalParams; return gFalse; } unlockGlobalParams; return gTrue; } void GlobalParams::setTextPageBreaks(GBool pageBreaks) { lockGlobalParams; textPageBreaks = pageBreaks; unlockGlobalParams; } void GlobalParams::setTextKeepTinyChars(GBool keep) { lockGlobalParams; textKeepTinyChars = keep; unlockGlobalParams; } void GlobalParams::setInitialZoom(char *s) { lockGlobalParams; delete initialZoom; initialZoom = new GString(s); unlockGlobalParams; } void GlobalParams::setContinuousView(GBool cont) { lockGlobalParams; continuousView = cont; unlockGlobalParams; } GBool GlobalParams::setEnableT1lib(char *s) { GBool ok; lockGlobalParams; ok = parseYesNo2(s, &enableT1lib); unlockGlobalParams; return ok; } GBool GlobalParams::setEnableFreeType(char *s) { GBool ok; lockGlobalParams; ok = parseYesNo2(s, &enableFreeType); unlockGlobalParams; return ok; } GBool GlobalParams::setAntialias(char *s) { GBool ok; lockGlobalParams; ok = parseYesNo2(s, &antialias); unlockGlobalParams; return ok; } GBool GlobalParams::setVectorAntialias(char *s) { GBool ok; lockGlobalParams; ok = parseYesNo2(s, &vectorAntialias); unlockGlobalParams; return ok; } void GlobalParams::setScreenType(ScreenType t) { lockGlobalParams; screenType = t; unlockGlobalParams; } void GlobalParams::setScreenSize(int size) { lockGlobalParams; screenSize = size; unlockGlobalParams; } void GlobalParams::setScreenDotRadius(int r) { lockGlobalParams; screenDotRadius = r; unlockGlobalParams; } void GlobalParams::setScreenGamma(double gamma) { lockGlobalParams; screenGamma = gamma; unlockGlobalParams; } void GlobalParams::setScreenBlackThreshold(double thresh) { lockGlobalParams; screenBlackThreshold = thresh; unlockGlobalParams; } void GlobalParams::setScreenWhiteThreshold(double thresh) { lockGlobalParams; screenWhiteThreshold = thresh; unlockGlobalParams; } void GlobalParams::setMapNumericCharNames(GBool map) { lockGlobalParams; mapNumericCharNames = map; unlockGlobalParams; } void GlobalParams::setMapUnknownCharNames(GBool map) { lockGlobalParams; mapUnknownCharNames = map; unlockGlobalParams; } void GlobalParams::setPrintCommands(GBool printCommandsA) { lockGlobalParams; printCommands = printCommandsA; unlockGlobalParams; } void GlobalParams::setErrQuiet(GBool errQuietA) { lockGlobalParams; errQuiet = errQuietA; unlockGlobalParams; } void GlobalParams::addSecurityHandler(XpdfSecurityHandler *handler) { #ifdef ENABLE_PLUGINS lockGlobalParams; securityHandlers->append(handler); unlockGlobalParams; #endif } XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) { #ifdef ENABLE_PLUGINS XpdfSecurityHandler *hdlr; int i; lockGlobalParams; for (i = 0; i < securityHandlers->getLength(); ++i) { hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); if (!strcasecmp(hdlr->name, name)) { unlockGlobalParams; return hdlr; } } unlockGlobalParams; if (!loadPlugin("security", name)) { return NULL; } lockGlobalParams; for (i = 0; i < securityHandlers->getLength(); ++i) { hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); if (!strcmp(hdlr->name, name)) { unlockGlobalParams; return hdlr; } } unlockGlobalParams; #endif return NULL; } #ifdef ENABLE_PLUGINS //------------------------------------------------------------------------ // plugins //------------------------------------------------------------------------ GBool GlobalParams::loadPlugin(char *type, char *name) { Plugin *plugin; if (!(plugin = Plugin::load(type, name))) { return gFalse; } lockGlobalParams; plugins->append(plugin); unlockGlobalParams; return gTrue; } #endif // ENABLE_PLUGINS xpdf-3.03/xpdf/GlobalParams.h0000644000076400007640000004120211622305345015370 0ustar dereknderekn//======================================================================== // // GlobalParams.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GLOBALPARAMS_H #define GLOBALPARAMS_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "gtypes.h" #include "CharTypes.h" #if MULTITHREADED #include "GMutex.h" #endif class GString; class GList; class GHash; class NameToCharCode; class CharCodeToUnicode; class CharCodeToUnicodeCache; class UnicodeMap; class UnicodeMapCache; class CMap; class CMapCache; struct XpdfSecurityHandler; class GlobalParams; class SysFontList; //------------------------------------------------------------------------ // The global parameters object. extern GlobalParams *globalParams; //------------------------------------------------------------------------ enum SysFontType { sysFontPFA, sysFontPFB, sysFontTTF, sysFontTTC }; //------------------------------------------------------------------------ class PSFontParam16 { public: GString *name; // PDF font name for psResidentFont16; // char collection name for psResidentFontCC int wMode; // writing mode (0=horiz, 1=vert) GString *psFontName; // PostScript font name GString *encoding; // encoding PSFontParam16(GString *nameA, int wModeA, GString *psFontNameA, GString *encodingA); ~PSFontParam16(); }; //------------------------------------------------------------------------ enum PSLevel { psLevel1, psLevel1Sep, psLevel2, psLevel2Sep, psLevel3, psLevel3Sep }; //------------------------------------------------------------------------ enum EndOfLineKind { eolUnix, // LF eolDOS, // CR+LF eolMac // CR }; //------------------------------------------------------------------------ enum ScreenType { screenUnset, screenDispersed, screenClustered, screenStochasticClustered }; //------------------------------------------------------------------------ class KeyBinding { public: int code; // 0x20 .. 0xfe = ASCII, // >=0x10000 = special keys, mouse buttons, // etc. (xpdfKeyCode* symbols) int mods; // modifiers (xpdfKeyMod* symbols, or-ed // together) int context; // context (xpdfKeyContext* symbols, or-ed // together) GList *cmds; // list of commands [GString] KeyBinding(int codeA, int modsA, int contextA, const char *cmd0); KeyBinding(int codeA, int modsA, int contextA, const char *cmd0, const char *cmd1); KeyBinding(int codeA, int modsA, int contextA, GList *cmdsA); ~KeyBinding(); }; #define xpdfKeyCodeTab 0x1000 #define xpdfKeyCodeReturn 0x1001 #define xpdfKeyCodeEnter 0x1002 #define xpdfKeyCodeBackspace 0x1003 #define xpdfKeyCodeInsert 0x1004 #define xpdfKeyCodeDelete 0x1005 #define xpdfKeyCodeHome 0x1006 #define xpdfKeyCodeEnd 0x1007 #define xpdfKeyCodePgUp 0x1008 #define xpdfKeyCodePgDn 0x1009 #define xpdfKeyCodeLeft 0x100a #define xpdfKeyCodeRight 0x100b #define xpdfKeyCodeUp 0x100c #define xpdfKeyCodeDown 0x100d #define xpdfKeyCodeF1 0x1100 #define xpdfKeyCodeF35 0x1122 #define xpdfKeyCodeMousePress1 0x2001 #define xpdfKeyCodeMousePress2 0x2002 #define xpdfKeyCodeMousePress3 0x2003 #define xpdfKeyCodeMousePress4 0x2004 #define xpdfKeyCodeMousePress5 0x2005 #define xpdfKeyCodeMousePress6 0x2006 #define xpdfKeyCodeMousePress7 0x2007 // ... #define xpdfKeyCodeMousePress32 0x2020 #define xpdfKeyCodeMouseRelease1 0x2101 #define xpdfKeyCodeMouseRelease2 0x2102 #define xpdfKeyCodeMouseRelease3 0x2103 #define xpdfKeyCodeMouseRelease4 0x2104 #define xpdfKeyCodeMouseRelease5 0x2105 #define xpdfKeyCodeMouseRelease6 0x2106 #define xpdfKeyCodeMouseRelease7 0x2107 // ... #define xpdfKeyCodeMouseRelease32 0x2120 #define xpdfKeyModNone 0 #define xpdfKeyModShift (1 << 0) #define xpdfKeyModCtrl (1 << 1) #define xpdfKeyModAlt (1 << 2) #define xpdfKeyContextAny 0 #define xpdfKeyContextFullScreen (1 << 0) #define xpdfKeyContextWindow (2 << 0) #define xpdfKeyContextContinuous (1 << 2) #define xpdfKeyContextSinglePage (2 << 2) #define xpdfKeyContextOverLink (1 << 4) #define xpdfKeyContextOffLink (2 << 4) #define xpdfKeyContextOutline (1 << 6) #define xpdfKeyContextMainWin (2 << 6) #define xpdfKeyContextScrLockOn (1 << 8) #define xpdfKeyContextScrLockOff (2 << 8) //------------------------------------------------------------------------ class GlobalParams { public: // Initialize the global parameters by attempting to read a config // file. GlobalParams(char *cfgFileName); ~GlobalParams(); void setBaseDir(char *dir); void setupBaseFonts(char *dir); void parseLine(char *buf, GString *fileName, int line); //----- accessors CharCode getMacRomanCharCode(char *charName); GString *getBaseDir(); Unicode mapNameToUnicode(const char *charName); UnicodeMap *getResidentUnicodeMap(GString *encodingName); FILE *getUnicodeMapFile(GString *encodingName); FILE *findCMapFile(GString *collection, GString *cMapName); FILE *findToUnicodeFile(GString *name); GString *findFontFile(GString *fontName); GString *findSystemFontFile(GString *fontName, SysFontType *type, int *fontNum); GString *findCCFontFile(GString *collection); GString *getPSFile(); int getPSPaperWidth(); int getPSPaperHeight(); void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); GBool getPSDuplex(); GBool getPSCrop(); GBool getPSExpandSmaller(); GBool getPSShrinkLarger(); GBool getPSCenter(); PSLevel getPSLevel(); GString *getPSResidentFont(GString *fontName); GList *getPSResidentFonts(); PSFontParam16 *getPSResidentFont16(GString *fontName, int wMode); PSFontParam16 *getPSResidentFontCC(GString *collection, int wMode); GBool getPSEmbedType1(); GBool getPSEmbedTrueType(); GBool getPSEmbedCIDPostScript(); GBool getPSEmbedCIDTrueType(); GBool getPSFontPassthrough(); GBool getPSPreload(); GBool getPSOPI(); GBool getPSASCIIHex(); GBool getPSUncompressPreloadedImages(); double getPSRasterResolution(); GBool getPSRasterMono(); GBool getPSAlwaysRasterize(); GString *getTextEncodingName(); EndOfLineKind getTextEOL(); GBool getTextPageBreaks(); GBool getTextKeepTinyChars(); GString *getInitialZoom(); GBool getContinuousView(); GBool getEnableT1lib(); GBool getEnableFreeType(); GBool getDisableFreeTypeHinting(); GBool getAntialias(); GBool getVectorAntialias(); GBool getAntialiasPrinting(); GBool getStrokeAdjust(); ScreenType getScreenType(); int getScreenSize(); int getScreenDotRadius(); double getScreenGamma(); double getScreenBlackThreshold(); double getScreenWhiteThreshold(); double getMinLineWidth(); GBool getDrawAnnotations(); GBool getOverprintPreview() { return overprintPreview; } GString *getLaunchCommand() { return launchCommand; } GString *getURLCommand() { return urlCommand; } GString *getMovieCommand() { return movieCommand; } GBool getMapNumericCharNames(); GBool getMapUnknownCharNames(); GList *getKeyBinding(int code, int mods, int context); GBool getPrintCommands(); GBool getErrQuiet(); CharCodeToUnicode *getCIDToUnicode(GString *collection); CharCodeToUnicode *getUnicodeToUnicode(GString *fontName); UnicodeMap *getUnicodeMap(GString *encodingName); CMap *getCMap(GString *collection, GString *cMapName); UnicodeMap *getTextEncoding(); //----- functions to set parameters void addFontFile(GString *fontName, GString *path); void setPSFile(char *file); GBool setPSPaperSize(char *size); void setPSPaperWidth(int width); void setPSPaperHeight(int height); void setPSImageableArea(int llx, int lly, int urx, int ury); void setPSDuplex(GBool duplex); void setPSCrop(GBool crop); void setPSExpandSmaller(GBool expand); void setPSShrinkLarger(GBool shrink); void setPSCenter(GBool center); void setPSLevel(PSLevel level); void setPSEmbedType1(GBool embed); void setPSEmbedTrueType(GBool embed); void setPSEmbedCIDPostScript(GBool embed); void setPSEmbedCIDTrueType(GBool embed); void setPSFontPassthrough(GBool passthrough); void setPSPreload(GBool preload); void setPSOPI(GBool opi); void setPSASCIIHex(GBool hex); void setTextEncoding(char *encodingName); GBool setTextEOL(char *s); void setTextPageBreaks(GBool pageBreaks); void setTextKeepTinyChars(GBool keep); void setInitialZoom(char *s); void setContinuousView(GBool cont); GBool setEnableT1lib(char *s); GBool setEnableFreeType(char *s); GBool setAntialias(char *s); GBool setVectorAntialias(char *s); void setScreenType(ScreenType t); void setScreenSize(int size); void setScreenDotRadius(int r); void setScreenGamma(double gamma); void setScreenBlackThreshold(double thresh); void setScreenWhiteThreshold(double thresh); void setMapNumericCharNames(GBool map); void setMapUnknownCharNames(GBool map); void setPrintCommands(GBool printCommandsA); void setErrQuiet(GBool errQuietA); //----- security handlers void addSecurityHandler(XpdfSecurityHandler *handler); XpdfSecurityHandler *getSecurityHandler(char *name); private: void createDefaultKeyBindings(); void parseFile(GString *fileName, FILE *f); void parseNameToUnicode(GList *tokens, GString *fileName, int line); void parseCIDToUnicode(GList *tokens, GString *fileName, int line); void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line); void parseUnicodeMap(GList *tokens, GString *fileName, int line); void parseCMapDir(GList *tokens, GString *fileName, int line); void parseToUnicodeDir(GList *tokens, GString *fileName, int line); void parseFontFile(GList *tokens, GString *fileName, int line); void parseFontDir(GList *tokens, GString *fileName, int line); void parseFontFileCC(GList *tokens, GString *fileName, int line); void parsePSFile(GList *tokens, GString *fileName, int line); void parsePSPaperSize(GList *tokens, GString *fileName, int line); void parsePSImageableArea(GList *tokens, GString *fileName, int line); void parsePSLevel(GList *tokens, GString *fileName, int line); void parsePSResidentFont(GList *tokens, GString *fileName, int line); void parsePSResidentFont16(GList *tokens, GString *fileName, int line); void parsePSResidentFontCC(GList *tokens, GString *fileName, int line); void parseTextEncoding(GList *tokens, GString *fileName, int line); void parseTextEOL(GList *tokens, GString *fileName, int line); void parseInitialZoom(GList *tokens, GString *fileName, int line); void parseScreenType(GList *tokens, GString *fileName, int line); void parseBind(GList *tokens, GString *fileName, int line); void parseUnbind(GList *tokens, GString *fileName, int line); GBool parseKey(GString *modKeyStr, GString *contextStr, int *code, int *mods, int *context, const char *cmdName, GList *tokens, GString *fileName, int line); void parseCommand(const char *cmdName, GString **val, GList *tokens, GString *fileName, int line); void parseYesNo(const char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line); GBool parseYesNo2(char *token, GBool *flag); void parseInteger(const char *cmdName, int *val, GList *tokens, GString *fileName, int line); void parseFloat(const char *cmdName, double *val, GList *tokens, GString *fileName, int line); UnicodeMap *getUnicodeMap2(GString *encodingName); #ifdef ENABLE_PLUGINS GBool loadPlugin(char *type, char *name); #endif //----- static tables NameToCharCode * // mapping from char name to macRomanReverseMap; // MacRomanEncoding index //----- user-modifiable settings GString *baseDir; // base directory - for plugins, etc. NameToCharCode * // mapping from char name to Unicode nameToUnicode; GHash *cidToUnicodes; // files for mappings from char collections // to Unicode, indexed by collection name // [GString] GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings, // indexed by font name pattern [GString] GHash *residentUnicodeMaps; // mappings from Unicode to char codes, // indexed by encoding name [UnicodeMap] GHash *unicodeMaps; // files for mappings from Unicode to char // codes, indexed by encoding name [GString] GHash *cMapDirs; // list of CMap dirs, indexed by collection // name [GList[GString]] GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] GHash *fontFiles; // font files: font name mapped to path // [GString] GList *fontDirs; // list of font dirs [GString] GHash *ccFontFiles; // character collection font files: // collection name mapped to path [GString] SysFontList *sysFonts; // system fonts GString *psFile; // PostScript file or command (for xpdf) int psPaperWidth; // paper size, in PostScript points, for int psPaperHeight; // PostScript output int psImageableLLX, // imageable area, in PostScript points, psImageableLLY, // for PostScript output psImageableURX, psImageableURY; GBool psCrop; // crop PS output to CropBox GBool psExpandSmaller; // expand smaller pages to fill paper GBool psShrinkLarger; // shrink larger pages to fit paper GBool psCenter; // center pages on the paper GBool psDuplex; // enable duplexing in PostScript? PSLevel psLevel; // PostScript level to generate GHash *psResidentFonts; // 8-bit fonts resident in printer: // PDF font name mapped to PS font name // [GString] GList *psResidentFonts16; // 16-bit fonts resident in printer: // PDF font name mapped to font info // [PSFontParam16] GList *psResidentFontsCC; // 16-bit character collection fonts // resident in printer: collection name // mapped to font info [PSFontParam16] GBool psEmbedType1; // embed Type 1 fonts? GBool psEmbedTrueType; // embed TrueType fonts? GBool psEmbedCIDPostScript; // embed CID PostScript fonts? GBool psEmbedCIDTrueType; // embed CID TrueType fonts? GBool psFontPassthrough; // pass all fonts through as-is? GBool psPreload; // preload PostScript images and forms into // memory GBool psOPI; // generate PostScript OPI comments? GBool psASCIIHex; // use ASCIIHex instead of ASCII85? GBool psUncompressPreloadedImages; // uncompress all preloaded images double psRasterResolution; // PostScript rasterization resolution (dpi) GBool psRasterMono; // true to do PostScript rasterization // in monochrome (gray); false to do it // in color (RGB/CMYK) GBool psAlwaysRasterize; // force PostScript rasterization GString *textEncoding; // encoding (unicodeMap) to use for text // output EndOfLineKind textEOL; // type of EOL marker to use for text // output GBool textPageBreaks; // insert end-of-page markers? GBool textKeepTinyChars; // keep all characters in text output GString *initialZoom; // initial zoom level GBool continuousView; // continuous view mode GBool enableT1lib; // t1lib enable flag GBool enableFreeType; // FreeType enable flag GBool disableFreeTypeHinting; // FreeType hinting disable flag GBool antialias; // font anti-aliasing enable flag GBool vectorAntialias; // vector anti-aliasing enable flag GBool antialiasPrinting; // allow anti-aliasing when printing GBool strokeAdjust; // stroke adjustment enable flag ScreenType screenType; // halftone screen type int screenSize; // screen matrix size int screenDotRadius; // screen dot radius double screenGamma; // screen gamma correction double screenBlackThreshold; // screen black clamping threshold double screenWhiteThreshold; // screen white clamping threshold double minLineWidth; // minimum line width GBool drawAnnotations; // draw annotations or not GBool overprintPreview; // enable overprint preview GString *launchCommand; // command executed for 'launch' links GString *urlCommand; // command executed for URL links GString *movieCommand; // command executed for movie annotations GBool mapNumericCharNames; // map numeric char names (from font subsets)? GBool mapUnknownCharNames; // map unknown char names? GList *keyBindings; // key & mouse button bindings [KeyBinding] GBool printCommands; // print the drawing commands GBool errQuiet; // suppress error messages? CharCodeToUnicodeCache *cidToUnicodeCache; CharCodeToUnicodeCache *unicodeToUnicodeCache; UnicodeMapCache *unicodeMapCache; CMapCache *cMapCache; #ifdef ENABLE_PLUGINS GList *plugins; // list of plugins [Plugin] GList *securityHandlers; // list of loaded security handlers // [XpdfSecurityHandler] #endif #if MULTITHREADED GMutex mutex; GMutex unicodeMapCacheMutex; GMutex cMapCacheMutex; #endif }; #endif xpdf-3.03/xpdf/Link.h0000644000076400007640000002220411622305345013722 0ustar dereknderekn//======================================================================== // // Link.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef LINK_H #define LINK_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "Object.h" class GString; class Array; class Dict; //------------------------------------------------------------------------ // LinkAction //------------------------------------------------------------------------ enum LinkActionKind { actionGoTo, // go to destination actionGoToR, // go to destination in new file actionLaunch, // launch app (or open document) actionURI, // URI actionNamed, // named action actionMovie, // movie action actionUnknown // anything else }; class LinkAction { public: // Destructor. virtual ~LinkAction() {} // Was the LinkAction created successfully? virtual GBool isOk() = 0; // Check link action type. virtual LinkActionKind getKind() = 0; // Parse a destination (old-style action) name, string, or array. static LinkAction *parseDest(Object *obj); // Parse an action dictionary. static LinkAction *parseAction(Object *obj, GString *baseURI = NULL); // Extract a file name from a file specification (string or // dictionary). static GString *getFileSpecName(Object *fileSpecObj); }; //------------------------------------------------------------------------ // LinkDest //------------------------------------------------------------------------ enum LinkDestKind { destXYZ, destFit, destFitH, destFitV, destFitR, destFitB, destFitBH, destFitBV }; class LinkDest { public: // Build a LinkDest from the array. LinkDest(Array *a); // Copy a LinkDest. LinkDest *copy() { return new LinkDest(this); } // Was the LinkDest created successfully? GBool isOk() { return ok; } // Accessors. LinkDestKind getKind() { return kind; } GBool isPageRef() { return pageIsRef; } int getPageNum() { return pageNum; } Ref getPageRef() { return pageRef; } double getLeft() { return left; } double getBottom() { return bottom; } double getRight() { return right; } double getTop() { return top; } double getZoom() { return zoom; } GBool getChangeLeft() { return changeLeft; } GBool getChangeTop() { return changeTop; } GBool getChangeZoom() { return changeZoom; } private: LinkDestKind kind; // destination type GBool pageIsRef; // is the page a reference or number? union { Ref pageRef; // reference to page int pageNum; // one-relative page number }; double left, bottom; // position double right, top; double zoom; // zoom factor GBool changeLeft, changeTop; // which position components to change: GBool changeZoom; // destXYZ uses all three; // destFitH/BH use changeTop; // destFitV/BV use changeLeft GBool ok; // set if created successfully LinkDest(LinkDest *dest); }; //------------------------------------------------------------------------ // LinkGoTo //------------------------------------------------------------------------ class LinkGoTo: public LinkAction { public: // Build a LinkGoTo from a destination (dictionary, name, or string). LinkGoTo(Object *destObj); // Destructor. virtual ~LinkGoTo(); // Was the LinkGoTo created successfully? virtual GBool isOk() { return dest || namedDest; } // Accessors. virtual LinkActionKind getKind() { return actionGoTo; } LinkDest *getDest() { return dest; } GString *getNamedDest() { return namedDest; } private: LinkDest *dest; // regular destination (NULL for remote // link with bad destination) GString *namedDest; // named destination (only one of dest and // and namedDest may be non-NULL) }; //------------------------------------------------------------------------ // LinkGoToR //------------------------------------------------------------------------ class LinkGoToR: public LinkAction { public: // Build a LinkGoToR from a file spec (dictionary) and destination // (dictionary, name, or string). LinkGoToR(Object *fileSpecObj, Object *destObj); // Destructor. virtual ~LinkGoToR(); // Was the LinkGoToR created successfully? virtual GBool isOk() { return fileName && (dest || namedDest); } // Accessors. virtual LinkActionKind getKind() { return actionGoToR; } GString *getFileName() { return fileName; } LinkDest *getDest() { return dest; } GString *getNamedDest() { return namedDest; } private: GString *fileName; // file name LinkDest *dest; // regular destination (NULL for remote // link with bad destination) GString *namedDest; // named destination (only one of dest and // and namedDest may be non-NULL) }; //------------------------------------------------------------------------ // LinkLaunch //------------------------------------------------------------------------ class LinkLaunch: public LinkAction { public: // Build a LinkLaunch from an action dictionary. LinkLaunch(Object *actionObj); // Destructor. virtual ~LinkLaunch(); // Was the LinkLaunch created successfully? virtual GBool isOk() { return fileName != NULL; } // Accessors. virtual LinkActionKind getKind() { return actionLaunch; } GString *getFileName() { return fileName; } GString *getParams() { return params; } private: GString *fileName; // file name GString *params; // parameters }; //------------------------------------------------------------------------ // LinkURI //------------------------------------------------------------------------ class LinkURI: public LinkAction { public: // Build a LinkURI given the URI (string) and base URI. LinkURI(Object *uriObj, GString *baseURI); // Destructor. virtual ~LinkURI(); // Was the LinkURI created successfully? virtual GBool isOk() { return uri != NULL; } // Accessors. virtual LinkActionKind getKind() { return actionURI; } GString *getURI() { return uri; } private: GString *uri; // the URI }; //------------------------------------------------------------------------ // LinkNamed //------------------------------------------------------------------------ class LinkNamed: public LinkAction { public: // Build a LinkNamed given the action name. LinkNamed(Object *nameObj); virtual ~LinkNamed(); virtual GBool isOk() { return name != NULL; } virtual LinkActionKind getKind() { return actionNamed; } GString *getName() { return name; } private: GString *name; }; //------------------------------------------------------------------------ // LinkMovie //------------------------------------------------------------------------ class LinkMovie: public LinkAction { public: LinkMovie(Object *annotObj, Object *titleObj); virtual ~LinkMovie(); virtual GBool isOk() { return annotRef.num >= 0 || title != NULL; } virtual LinkActionKind getKind() { return actionMovie; } GBool hasAnnotRef() { return annotRef.num >= 0; } Ref *getAnnotRef() { return &annotRef; } GString *getTitle() { return title; } private: Ref annotRef; GString *title; }; //------------------------------------------------------------------------ // LinkUnknown //------------------------------------------------------------------------ class LinkUnknown: public LinkAction { public: // Build a LinkUnknown with the specified action type. LinkUnknown(char *actionA); // Destructor. virtual ~LinkUnknown(); // Was the LinkUnknown create successfully? virtual GBool isOk() { return action != NULL; } // Accessors. virtual LinkActionKind getKind() { return actionUnknown; } GString *getAction() { return action; } private: GString *action; // action subtype }; //------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ class Link { public: // Construct a link, given its dictionary. Link(Dict *dict, GString *baseURI); // Destructor. ~Link(); // Was the link created successfully? GBool isOk() { return ok; } // Check if point is inside the link rectangle. GBool inRect(double x, double y) { return x1 <= x && x <= x2 && y1 <= y && y <= y2; } // Get action. LinkAction *getAction() { return action; } // Get the link rectangle. void getRect(double *xa1, double *ya1, double *xa2, double *ya2) { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } private: double x1, y1; // lower left corner double x2, y2; // upper right corner LinkAction *action; // action GBool ok; // is link valid? }; //------------------------------------------------------------------------ // Links //------------------------------------------------------------------------ class Links { public: // Extract links from array of annotations. Links(Object *annots, GString *baseURI); // Destructor. ~Links(); // Iterate through list of links. int getNumLinks() { return numLinks; } Link *getLink(int i) { return links[i]; } // If point , is in a link, return the associated action; // else return NULL. LinkAction *find(double x, double y); // Return true if , is in a link. GBool onLink(double x, double y); private: Link **links; int numLinks; }; #endif xpdf-3.03/xpdf/Annot.h0000644000076400007640000001003311622305345014101 0ustar dereknderekn//======================================================================== // // Annot.h // // Copyright 2000-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ANNOT_H #define ANNOT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif class XRef; class Catalog; class Gfx; class GfxFontDict; class PDFDoc; //------------------------------------------------------------------------ // AnnotBorderStyle //------------------------------------------------------------------------ enum AnnotBorderType { annotBorderSolid, annotBorderDashed, annotBorderBeveled, annotBorderInset, annotBorderUnderlined }; class AnnotBorderStyle { public: AnnotBorderStyle(AnnotBorderType typeA, double widthA, double *dashA, int dashLengthA, double rA, double gA, double bA); ~AnnotBorderStyle(); AnnotBorderType getType() { return type; } double getWidth() { return width; } void getDash(double **dashA, int *dashLengthA) { *dashA = dash; *dashLengthA = dashLength; } void getColor(double *rA, double *gA, double *bA) { *rA = r; *gA = g; *bA = b; } private: AnnotBorderType type; double width; double *dash; int dashLength; double r, g, b; }; //------------------------------------------------------------------------ // Annot //------------------------------------------------------------------------ class Annot { public: Annot(PDFDoc *docA, Dict *dict, Ref *refA); ~Annot(); GBool isOk() { return ok; } void draw(Gfx *gfx, GBool printing); GString *getType() { return type; } double getXMin() { return xMin; } double getYMin() { return yMin; } double getXMax() { return xMax; } double getYMax() { return yMax; } Object *getObject(Object *obj); // Get appearance object. Object *getAppearance(Object *obj) { return appearance.fetch(xref, obj); } AnnotBorderStyle *getBorderStyle() { return borderStyle; } GBool match(Ref *refA) { return ref.num == refA->num && ref.gen == refA->gen; } void generateFieldAppearance(Dict *field, Dict *annot, Dict *acroForm); private: void setColor(Array *a, GBool fill, int adjust); void drawText(GString *text, GString *da, GfxFontDict *fontDict, GBool multiline, int comb, int quadding, GBool txField, GBool forceZapfDingbats, int rot); void drawListBox(GString **text, GBool *selection, int nOptions, int topIdx, GString *da, GfxFontDict *fontDict, GBool quadding); void getNextLine(GString *text, int start, GfxFont *font, double fontSize, double wMax, int *end, double *width, int *next); void drawCircle(double cx, double cy, double r, GBool fill); void drawCircleTopLeft(double cx, double cy, double r); void drawCircleBottomRight(double cx, double cy, double r); Object *fieldLookup(Dict *field, Dict *acroForm, const char *key, Object *obj); PDFDoc *doc; XRef *xref; // the xref table for this PDF file Ref ref; // object ref identifying this annotation GString *type; // annotation type GString *appearanceState; // appearance state name Object appearance; // a reference to the Form XObject stream // for the normal appearance GString *appearBuf; double xMin, yMin, // annotation rectangle xMax, yMax; Guint flags; AnnotBorderStyle *borderStyle; Object ocObj; // optional content entry GBool ok; }; //------------------------------------------------------------------------ // Annots //------------------------------------------------------------------------ class Annots { public: // Build a list of Annot objects. Annots(PDFDoc *docA, Object *annotsObj); ~Annots(); // Iterate through list of annotations. int getNumAnnots() { return nAnnots; } Annot *getAnnot(int i) { return annots[i]; } // (Re)generate the appearance streams for all annotations belonging // to a form field. void generateAppearances(); private: void scanFieldAppearances(Dict *node, Ref *ref, Dict *parent, Dict *acroForm); Annot *findAnnot(Ref *ref); PDFDoc *doc; Annot **annots; int nAnnots; }; #endif xpdf-3.03/xpdf/Function.h0000644000076400007640000001435311622305345014620 0ustar dereknderekn//======================================================================== // // Function.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FUNCTION_H #define FUNCTION_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" class Dict; class Stream; struct PSObject; class PSStack; //------------------------------------------------------------------------ // Function //------------------------------------------------------------------------ #define funcMaxInputs 32 #define funcMaxOutputs 32 #define sampledFuncMaxInputs 16 class Function { public: Function(); virtual ~Function(); // Construct a function. Returns NULL if unsuccessful. static Function *parse(Object *funcObj, int recursion = 0); // Initialize the entries common to all function types. GBool init(Dict *dict); virtual Function *copy() = 0; // Return the function type: // -1 : identity // 0 : sampled // 2 : exponential // 3 : stitching // 4 : PostScript virtual int getType() = 0; // Return size of input and output tuples. int getInputSize() { return m; } int getOutputSize() { return n; } double getDomainMin(int i) { return domain[i][0]; } double getDomainMax(int i) { return domain[i][1]; } double getRangeMin(int i) { return range[i][0]; } double getRangeMax(int i) { return range[i][1]; } GBool getHasRange() { return hasRange; } // Transform an input tuple into an output tuple. virtual void transform(double *in, double *out) = 0; virtual GBool isOk() = 0; protected: int m, n; // size of input and output tuples double // min and max values for function domain domain[funcMaxInputs][2]; double // min and max values for function range range[funcMaxOutputs][2]; GBool hasRange; // set if range is defined }; //------------------------------------------------------------------------ // IdentityFunction //------------------------------------------------------------------------ class IdentityFunction: public Function { public: IdentityFunction(); virtual ~IdentityFunction(); virtual Function *copy() { return new IdentityFunction(); } virtual int getType() { return -1; } virtual void transform(double *in, double *out); virtual GBool isOk() { return gTrue; } private: }; //------------------------------------------------------------------------ // SampledFunction //------------------------------------------------------------------------ class SampledFunction: public Function { public: SampledFunction(Object *funcObj, Dict *dict); virtual ~SampledFunction(); virtual Function *copy() { return new SampledFunction(this); } virtual int getType() { return 0; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } int getSampleSize(int i) { return sampleSize[i]; } double getEncodeMin(int i) { return encode[i][0]; } double getEncodeMax(int i) { return encode[i][1]; } double getDecodeMin(int i) { return decode[i][0]; } double getDecodeMax(int i) { return decode[i][1]; } double *getSamples() { return samples; } private: SampledFunction(SampledFunction *func); int // number of samples for each domain element sampleSize[funcMaxInputs]; double // min and max values for domain encoder encode[funcMaxInputs][2]; double // min and max values for range decoder decode[funcMaxOutputs][2]; double // input multipliers inputMul[funcMaxInputs]; int *idxOffset; double *samples; // the samples int nSamples; // size of the samples array double *sBuf; // buffer for the transform function double cacheIn[funcMaxInputs]; double cacheOut[funcMaxOutputs]; GBool ok; }; //------------------------------------------------------------------------ // ExponentialFunction //------------------------------------------------------------------------ class ExponentialFunction: public Function { public: ExponentialFunction(Object *funcObj, Dict *dict); virtual ~ExponentialFunction(); virtual Function *copy() { return new ExponentialFunction(this); } virtual int getType() { return 2; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } double *getC0() { return c0; } double *getC1() { return c1; } double getE() { return e; } private: ExponentialFunction(ExponentialFunction *func); double c0[funcMaxOutputs]; double c1[funcMaxOutputs]; double e; GBool ok; }; //------------------------------------------------------------------------ // StitchingFunction //------------------------------------------------------------------------ class StitchingFunction: public Function { public: StitchingFunction(Object *funcObj, Dict *dict, int recursion); virtual ~StitchingFunction(); virtual Function *copy() { return new StitchingFunction(this); } virtual int getType() { return 3; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } int getNumFuncs() { return k; } Function *getFunc(int i) { return funcs[i]; } double *getBounds() { return bounds; } double *getEncode() { return encode; } double *getScale() { return scale; } private: StitchingFunction(StitchingFunction *func); int k; Function **funcs; double *bounds; double *encode; double *scale; GBool ok; }; //------------------------------------------------------------------------ // PostScriptFunction //------------------------------------------------------------------------ class PostScriptFunction: public Function { public: PostScriptFunction(Object *funcObj, Dict *dict); virtual ~PostScriptFunction(); virtual Function *copy() { return new PostScriptFunction(this); } virtual int getType() { return 4; } virtual void transform(double *in, double *out); virtual GBool isOk() { return ok; } GString *getCodeString() { return codeString; } private: PostScriptFunction(PostScriptFunction *func); GBool parseCode(Stream *str, int *codePtr); GString *getToken(Stream *str); void resizeCode(int newSize); void exec(PSStack *stack, int codePtr); GString *codeString; PSObject *code; int codeSize; double cacheIn[funcMaxInputs]; double cacheOut[funcMaxOutputs]; GBool ok; }; #endif xpdf-3.03/xpdf/BuiltinFontTables.cc0000644000076400007640000070010411622305345016555 0ustar dereknderekn//======================================================================== // // BuiltinFontTables.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include "FontEncodingTables.h" #include "BuiltinFontTables.h" static BuiltinFontWidth courierWidthsTab[] = { { "Ntilde", 600, NULL }, { "rcaron", 600, NULL }, { "kcommaaccent", 600, NULL }, { "Ncommaaccent", 600, NULL }, { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, { "Aogonek", 600, NULL }, { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, { "Iogonek", 600, NULL }, { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, { "F", 600, NULL }, { "G", 600, NULL }, { "H", 600, NULL }, { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, { "iogonek", 600, NULL }, { "L", 600, NULL }, { "backslash", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, { "omacron", 600, NULL }, { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, { "S", 600, NULL }, { "T", 600, NULL }, { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, { "W", 600, NULL }, { "equal", 600, NULL }, { "question", 600, NULL }, { "X", 600, NULL }, { "Y", 600, NULL }, { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, { "e", 600, NULL }, { "f", 600, NULL }, { "g", 600, NULL }, { "bullet", 600, NULL }, { "h", 600, NULL }, { "i", 600, NULL }, { "Oslash", 600, NULL }, { "dagger", 600, NULL }, { "j", 600, NULL }, { "k", 600, NULL }, { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, { "Gbreve", 600, NULL }, { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, { "Idotaccent", 600, NULL }, { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, { "lessequal", 600, NULL }, { "lozenge", 600, NULL }, { "parenright", 600, NULL }, { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, { "quotedblleft", 600, NULL }, { "hyphen", 600, NULL }, { "guilsinglright", 600, NULL }, { "quotesingle", 600, NULL }, { "eight", 600, NULL }, { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, { "Abreve", 600, NULL }, { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, { "Adieresis", 600, NULL }, { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, { "otilde", 600, NULL }, { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, { "umacron", 600, NULL }, { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, { "edieresis", 600, NULL }, { "idieresis", 600, NULL }, { "Eth", 600, NULL }, { "ae", 600, NULL }, { "asterisk", 600, NULL }, { "odieresis", 600, NULL }, { "Uacute", 600, NULL }, { "ugrave", 600, NULL }, { "five", 600, NULL }, { "nine", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, { "Ccedilla", 600, NULL }, { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, { "underscore", 600, NULL }, { "Euro", 600, NULL }, { "Dcroat", 600, NULL }, { "zero", 600, NULL }, { "multiply", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Racute", 600, NULL }, { "Ograve", 600, NULL }, { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, { "Dcaron", 600, NULL }, { "dcroat", 600, NULL }, { "scedilla", 600, NULL }, { "Oacute", 600, NULL }, { "Ocircumflex", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, { "racute", 600, NULL }, { "Tcaron", 600, NULL }, { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, { "dcaron", 600, NULL }, { "Uogonek", 600, NULL }, { "two", 600, NULL }, { "summation", 600, NULL }, { "Igrave", 600, NULL }, { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, { "Uring", 600, NULL }, { "Lcommaaccent", 600, NULL }, { "tcaron", 600, NULL }, { "eogonek", 600, NULL }, { "Delta", 600, NULL }, { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "ampersand", 600, NULL }, { "Iacute", 600, NULL }, { "lacute", 600, NULL }, { "igrave", 600, NULL }, { "Ncaron", 600, NULL }, { "plus", 600, NULL }, { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, { "section", 600, NULL }, { "dieresis", 600, NULL }, { "quotedblbase", 600, NULL }, { "iacute", 600, NULL }, { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, { "seven", 600, NULL }, { "Amacron", 600, NULL }, { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, { "notequal", 600, NULL }, { "Imacron", 600, NULL }, { "rcommaaccent", 600, NULL }, { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, { "cacute", 600, NULL }, { "Ecaron", 600, NULL }, { "braceright", 600, NULL }, { "icircumflex", 600, NULL }, { "quotedblright", 600, NULL }, { "amacron", 600, NULL }, { "sacute", 600, NULL }, { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, { "Rcaron", 600, NULL }, { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, { "quoteleft", 600, NULL }, { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierBoldWidthsTab[] = { { "Ntilde", 600, NULL }, { "rcaron", 600, NULL }, { "kcommaaccent", 600, NULL }, { "Ncommaaccent", 600, NULL }, { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, { "Aogonek", 600, NULL }, { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, { "Iogonek", 600, NULL }, { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, { "F", 600, NULL }, { "G", 600, NULL }, { "H", 600, NULL }, { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, { "omacron", 600, NULL }, { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, { "S", 600, NULL }, { "T", 600, NULL }, { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, { "W", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, { "Y", 600, NULL }, { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, { "e", 600, NULL }, { "f", 600, NULL }, { "g", 600, NULL }, { "bullet", 600, NULL }, { "h", 600, NULL }, { "i", 600, NULL }, { "Oslash", 600, NULL }, { "dagger", 600, NULL }, { "j", 600, NULL }, { "k", 600, NULL }, { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, { "Gbreve", 600, NULL }, { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, { "Idotaccent", 600, NULL }, { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, { "lessequal", 600, NULL }, { "lozenge", 600, NULL }, { "parenright", 600, NULL }, { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, { "quotesingle", 600, NULL }, { "eight", 600, NULL }, { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, { "Abreve", 600, NULL }, { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, { "Adieresis", 600, NULL }, { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, { "otilde", 600, NULL }, { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, { "umacron", 600, NULL }, { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, { "edieresis", 600, NULL }, { "idieresis", 600, NULL }, { "Eth", 600, NULL }, { "ae", 600, NULL }, { "asterisk", 600, NULL }, { "odieresis", 600, NULL }, { "Uacute", 600, NULL }, { "ugrave", 600, NULL }, { "nine", 600, NULL }, { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, { "Ccedilla", 600, NULL }, { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, { "underscore", 600, NULL }, { "Euro", 600, NULL }, { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, { "Racute", 600, NULL }, { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, { "Dcaron", 600, NULL }, { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, { "racute", 600, NULL }, { "Tcaron", 600, NULL }, { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, { "dcaron", 600, NULL }, { "Uogonek", 600, NULL }, { "two", 600, NULL }, { "summation", 600, NULL }, { "Igrave", 600, NULL }, { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, { "Uring", 600, NULL }, { "Lcommaaccent", 600, NULL }, { "tcaron", 600, NULL }, { "eogonek", 600, NULL }, { "Delta", 600, NULL }, { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, { "lacute", 600, NULL }, { "Ncaron", 600, NULL }, { "plus", 600, NULL }, { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, { "section", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, { "Amacron", 600, NULL }, { "seven", 600, NULL }, { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, { "notequal", 600, NULL }, { "Imacron", 600, NULL }, { "rcommaaccent", 600, NULL }, { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, { "cacute", 600, NULL }, { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, { "quotedblright", 600, NULL }, { "amacron", 600, NULL }, { "sacute", 600, NULL }, { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, { "Rcaron", 600, NULL }, { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, { "quoteleft", 600, NULL }, { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierBoldObliqueWidthsTab[] = { { "Ntilde", 600, NULL }, { "rcaron", 600, NULL }, { "kcommaaccent", 600, NULL }, { "Ncommaaccent", 600, NULL }, { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, { "Aogonek", 600, NULL }, { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, { "Iogonek", 600, NULL }, { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, { "F", 600, NULL }, { "G", 600, NULL }, { "H", 600, NULL }, { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, { "omacron", 600, NULL }, { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, { "S", 600, NULL }, { "T", 600, NULL }, { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, { "W", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, { "Y", 600, NULL }, { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, { "e", 600, NULL }, { "f", 600, NULL }, { "g", 600, NULL }, { "bullet", 600, NULL }, { "h", 600, NULL }, { "i", 600, NULL }, { "Oslash", 600, NULL }, { "dagger", 600, NULL }, { "j", 600, NULL }, { "k", 600, NULL }, { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, { "Gbreve", 600, NULL }, { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, { "Idotaccent", 600, NULL }, { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, { "lessequal", 600, NULL }, { "lozenge", 600, NULL }, { "parenright", 600, NULL }, { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, { "quotesingle", 600, NULL }, { "eight", 600, NULL }, { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, { "Abreve", 600, NULL }, { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, { "Adieresis", 600, NULL }, { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, { "otilde", 600, NULL }, { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, { "umacron", 600, NULL }, { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, { "edieresis", 600, NULL }, { "idieresis", 600, NULL }, { "Eth", 600, NULL }, { "ae", 600, NULL }, { "asterisk", 600, NULL }, { "odieresis", 600, NULL }, { "Uacute", 600, NULL }, { "ugrave", 600, NULL }, { "nine", 600, NULL }, { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, { "Ccedilla", 600, NULL }, { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, { "underscore", 600, NULL }, { "Euro", 600, NULL }, { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, { "Racute", 600, NULL }, { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, { "Dcaron", 600, NULL }, { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, { "racute", 600, NULL }, { "Tcaron", 600, NULL }, { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, { "dcaron", 600, NULL }, { "Uogonek", 600, NULL }, { "two", 600, NULL }, { "summation", 600, NULL }, { "Igrave", 600, NULL }, { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, { "Uring", 600, NULL }, { "Lcommaaccent", 600, NULL }, { "tcaron", 600, NULL }, { "eogonek", 600, NULL }, { "Delta", 600, NULL }, { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, { "lacute", 600, NULL }, { "Ncaron", 600, NULL }, { "plus", 600, NULL }, { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, { "section", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, { "Amacron", 600, NULL }, { "seven", 600, NULL }, { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, { "notequal", 600, NULL }, { "Imacron", 600, NULL }, { "rcommaaccent", 600, NULL }, { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, { "cacute", 600, NULL }, { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, { "quotedblright", 600, NULL }, { "amacron", 600, NULL }, { "sacute", 600, NULL }, { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, { "Rcaron", 600, NULL }, { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, { "quoteleft", 600, NULL }, { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth courierObliqueWidthsTab[] = { { "Ntilde", 600, NULL }, { "rcaron", 600, NULL }, { "kcommaaccent", 600, NULL }, { "Ncommaaccent", 600, NULL }, { "Zacute", 600, NULL }, { "comma", 600, NULL }, { "cedilla", 600, NULL }, { "plusminus", 600, NULL }, { "circumflex", 600, NULL }, { "dotaccent", 600, NULL }, { "edotaccent", 600, NULL }, { "asciitilde", 600, NULL }, { "colon", 600, NULL }, { "onehalf", 600, NULL }, { "dollar", 600, NULL }, { "Lcaron", 600, NULL }, { "ntilde", 600, NULL }, { "Aogonek", 600, NULL }, { "ncommaaccent", 600, NULL }, { "minus", 600, NULL }, { "Iogonek", 600, NULL }, { "zacute", 600, NULL }, { "yen", 600, NULL }, { "space", 600, NULL }, { "Omacron", 600, NULL }, { "questiondown", 600, NULL }, { "emdash", 600, NULL }, { "Agrave", 600, NULL }, { "three", 600, NULL }, { "numbersign", 600, NULL }, { "lcaron", 600, NULL }, { "A", 600, NULL }, { "B", 600, NULL }, { "C", 600, NULL }, { "aogonek", 600, NULL }, { "D", 600, NULL }, { "E", 600, NULL }, { "onequarter", 600, NULL }, { "F", 600, NULL }, { "G", 600, NULL }, { "H", 600, NULL }, { "I", 600, NULL }, { "J", 600, NULL }, { "K", 600, NULL }, { "iogonek", 600, NULL }, { "backslash", 600, NULL }, { "L", 600, NULL }, { "periodcentered", 600, NULL }, { "M", 600, NULL }, { "N", 600, NULL }, { "omacron", 600, NULL }, { "Tcommaaccent", 600, NULL }, { "O", 600, NULL }, { "P", 600, NULL }, { "Q", 600, NULL }, { "Uhungarumlaut", 600, NULL }, { "R", 600, NULL }, { "Aacute", 600, NULL }, { "caron", 600, NULL }, { "S", 600, NULL }, { "T", 600, NULL }, { "U", 600, NULL }, { "agrave", 600, NULL }, { "V", 600, NULL }, { "W", 600, NULL }, { "X", 600, NULL }, { "question", 600, NULL }, { "equal", 600, NULL }, { "Y", 600, NULL }, { "Z", 600, NULL }, { "four", 600, NULL }, { "a", 600, NULL }, { "Gcommaaccent", 600, NULL }, { "b", 600, NULL }, { "c", 600, NULL }, { "d", 600, NULL }, { "e", 600, NULL }, { "f", 600, NULL }, { "g", 600, NULL }, { "bullet", 600, NULL }, { "h", 600, NULL }, { "i", 600, NULL }, { "Oslash", 600, NULL }, { "dagger", 600, NULL }, { "j", 600, NULL }, { "k", 600, NULL }, { "l", 600, NULL }, { "m", 600, NULL }, { "n", 600, NULL }, { "tcommaaccent", 600, NULL }, { "o", 600, NULL }, { "ordfeminine", 600, NULL }, { "ring", 600, NULL }, { "p", 600, NULL }, { "q", 600, NULL }, { "uhungarumlaut", 600, NULL }, { "r", 600, NULL }, { "twosuperior", 600, NULL }, { "aacute", 600, NULL }, { "s", 600, NULL }, { "OE", 600, NULL }, { "t", 600, NULL }, { "divide", 600, NULL }, { "u", 600, NULL }, { "Ccaron", 600, NULL }, { "v", 600, NULL }, { "w", 600, NULL }, { "x", 600, NULL }, { "y", 600, NULL }, { "z", 600, NULL }, { "Gbreve", 600, NULL }, { "commaaccent", 600, NULL }, { "hungarumlaut", 600, NULL }, { "Idotaccent", 600, NULL }, { "Nacute", 600, NULL }, { "quotedbl", 600, NULL }, { "gcommaaccent", 600, NULL }, { "mu", 600, NULL }, { "greaterequal", 600, NULL }, { "Scaron", 600, NULL }, { "Lslash", 600, NULL }, { "semicolon", 600, NULL }, { "oslash", 600, NULL }, { "lessequal", 600, NULL }, { "lozenge", 600, NULL }, { "parenright", 600, NULL }, { "ccaron", 600, NULL }, { "Ecircumflex", 600, NULL }, { "gbreve", 600, NULL }, { "trademark", 600, NULL }, { "daggerdbl", 600, NULL }, { "nacute", 600, NULL }, { "macron", 600, NULL }, { "Otilde", 600, NULL }, { "Emacron", 600, NULL }, { "ellipsis", 600, NULL }, { "scaron", 600, NULL }, { "AE", 600, NULL }, { "Ucircumflex", 600, NULL }, { "lslash", 600, NULL }, { "quotedblleft", 600, NULL }, { "guilsinglright", 600, NULL }, { "hyphen", 600, NULL }, { "quotesingle", 600, NULL }, { "eight", 600, NULL }, { "exclamdown", 600, NULL }, { "endash", 600, NULL }, { "oe", 600, NULL }, { "Abreve", 600, NULL }, { "Umacron", 600, NULL }, { "ecircumflex", 600, NULL }, { "Adieresis", 600, NULL }, { "copyright", 600, NULL }, { "Egrave", 600, NULL }, { "slash", 600, NULL }, { "Edieresis", 600, NULL }, { "otilde", 600, NULL }, { "Idieresis", 600, NULL }, { "parenleft", 600, NULL }, { "one", 600, NULL }, { "emacron", 600, NULL }, { "Odieresis", 600, NULL }, { "ucircumflex", 600, NULL }, { "bracketleft", 600, NULL }, { "Ugrave", 600, NULL }, { "quoteright", 600, NULL }, { "Udieresis", 600, NULL }, { "perthousand", 600, NULL }, { "Ydieresis", 600, NULL }, { "umacron", 600, NULL }, { "abreve", 600, NULL }, { "Eacute", 600, NULL }, { "adieresis", 600, NULL }, { "egrave", 600, NULL }, { "edieresis", 600, NULL }, { "idieresis", 600, NULL }, { "Eth", 600, NULL }, { "ae", 600, NULL }, { "asterisk", 600, NULL }, { "odieresis", 600, NULL }, { "Uacute", 600, NULL }, { "ugrave", 600, NULL }, { "nine", 600, NULL }, { "five", 600, NULL }, { "udieresis", 600, NULL }, { "Zcaron", 600, NULL }, { "Scommaaccent", 600, NULL }, { "threequarters", 600, NULL }, { "guillemotright", 600, NULL }, { "Ccedilla", 600, NULL }, { "ydieresis", 600, NULL }, { "tilde", 600, NULL }, { "at", 600, NULL }, { "eacute", 600, NULL }, { "underscore", 600, NULL }, { "Euro", 600, NULL }, { "Dcroat", 600, NULL }, { "multiply", 600, NULL }, { "zero", 600, NULL }, { "eth", 600, NULL }, { "Scedilla", 600, NULL }, { "Ograve", 600, NULL }, { "Racute", 600, NULL }, { "partialdiff", 600, NULL }, { "uacute", 600, NULL }, { "braceleft", 600, NULL }, { "Thorn", 600, NULL }, { "zcaron", 600, NULL }, { "scommaaccent", 600, NULL }, { "ccedilla", 600, NULL }, { "Dcaron", 600, NULL }, { "dcroat", 600, NULL }, { "Ocircumflex", 600, NULL }, { "Oacute", 600, NULL }, { "scedilla", 600, NULL }, { "ogonek", 600, NULL }, { "ograve", 600, NULL }, { "racute", 600, NULL }, { "Tcaron", 600, NULL }, { "Eogonek", 600, NULL }, { "thorn", 600, NULL }, { "degree", 600, NULL }, { "registered", 600, NULL }, { "radical", 600, NULL }, { "Aring", 600, NULL }, { "percent", 600, NULL }, { "six", 600, NULL }, { "paragraph", 600, NULL }, { "dcaron", 600, NULL }, { "Uogonek", 600, NULL }, { "two", 600, NULL }, { "summation", 600, NULL }, { "Igrave", 600, NULL }, { "Lacute", 600, NULL }, { "ocircumflex", 600, NULL }, { "oacute", 600, NULL }, { "Uring", 600, NULL }, { "Lcommaaccent", 600, NULL }, { "tcaron", 600, NULL }, { "eogonek", 600, NULL }, { "Delta", 600, NULL }, { "Ohungarumlaut", 600, NULL }, { "asciicircum", 600, NULL }, { "aring", 600, NULL }, { "grave", 600, NULL }, { "uogonek", 600, NULL }, { "bracketright", 600, NULL }, { "Iacute", 600, NULL }, { "ampersand", 600, NULL }, { "igrave", 600, NULL }, { "lacute", 600, NULL }, { "Ncaron", 600, NULL }, { "plus", 600, NULL }, { "uring", 600, NULL }, { "quotesinglbase", 600, NULL }, { "lcommaaccent", 600, NULL }, { "Yacute", 600, NULL }, { "ohungarumlaut", 600, NULL }, { "threesuperior", 600, NULL }, { "acute", 600, NULL }, { "section", 600, NULL }, { "dieresis", 600, NULL }, { "iacute", 600, NULL }, { "quotedblbase", 600, NULL }, { "ncaron", 600, NULL }, { "florin", 600, NULL }, { "yacute", 600, NULL }, { "Rcommaaccent", 600, NULL }, { "fi", 600, NULL }, { "fl", 600, NULL }, { "Acircumflex", 600, NULL }, { "Cacute", 600, NULL }, { "Icircumflex", 600, NULL }, { "guillemotleft", 600, NULL }, { "germandbls", 600, NULL }, { "Amacron", 600, NULL }, { "seven", 600, NULL }, { "Sacute", 600, NULL }, { "ordmasculine", 600, NULL }, { "dotlessi", 600, NULL }, { "sterling", 600, NULL }, { "notequal", 600, NULL }, { "Imacron", 600, NULL }, { "rcommaaccent", 600, NULL }, { "Zdotaccent", 600, NULL }, { "acircumflex", 600, NULL }, { "cacute", 600, NULL }, { "Ecaron", 600, NULL }, { "icircumflex", 600, NULL }, { "braceright", 600, NULL }, { "quotedblright", 600, NULL }, { "amacron", 600, NULL }, { "sacute", 600, NULL }, { "imacron", 600, NULL }, { "cent", 600, NULL }, { "currency", 600, NULL }, { "logicalnot", 600, NULL }, { "zdotaccent", 600, NULL }, { "Atilde", 600, NULL }, { "breve", 600, NULL }, { "bar", 600, NULL }, { "fraction", 600, NULL }, { "less", 600, NULL }, { "ecaron", 600, NULL }, { "guilsinglleft", 600, NULL }, { "exclam", 600, NULL }, { "period", 600, NULL }, { "Rcaron", 600, NULL }, { "Kcommaaccent", 600, NULL }, { "greater", 600, NULL }, { "atilde", 600, NULL }, { "brokenbar", 600, NULL }, { "quoteleft", 600, NULL }, { "Edotaccent", 600, NULL }, { "onesuperior", 600, NULL } }; static BuiltinFontWidth helveticaWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 333, NULL }, { "kcommaaccent", 500, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 278, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, { "Lcaron", 556, NULL }, { "ntilde", 556, NULL }, { "Aogonek", 667, NULL }, { "ncommaaccent", 556, NULL }, { "minus", 584, NULL }, { "Iogonek", 278, NULL }, { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, { "lcaron", 299, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, { "F", 611, NULL }, { "G", 778, NULL }, { "H", 722, NULL }, { "I", 278, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, { "iogonek", 222, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, { "omacron", 556, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, { "S", 667, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 556, NULL }, { "V", 667, NULL }, { "W", 944, NULL }, { "X", 667, NULL }, { "question", 556, NULL }, { "equal", 584, NULL }, { "Y", 667, NULL }, { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 500, NULL }, { "d", 556, NULL }, { "e", 556, NULL }, { "f", 278, NULL }, { "g", 556, NULL }, { "bullet", 350, NULL }, { "h", 556, NULL }, { "i", 222, NULL }, { "Oslash", 778, NULL }, { "dagger", 556, NULL }, { "j", 222, NULL }, { "k", 500, NULL }, { "l", 222, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, { "tcommaaccent", 278, NULL }, { "o", 556, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, { "uhungarumlaut", 556, NULL }, { "r", 333, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, { "s", 500, NULL }, { "OE", 1000, NULL }, { "t", 278, NULL }, { "divide", 584, NULL }, { "u", 556, NULL }, { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 500, NULL }, { "Gbreve", 778, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 278, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 355, NULL }, { "gcommaaccent", 556, NULL }, { "mu", 556, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 556, NULL }, { "semicolon", 278, NULL }, { "oslash", 611, NULL }, { "lessequal", 549, NULL }, { "lozenge", 471, NULL }, { "parenright", 333, NULL }, { "ccaron", 500, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 556, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 500, NULL }, { "AE", 1000, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 222, NULL }, { "quotedblleft", 333, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 191, NULL }, { "eight", 556, NULL }, { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, { "Abreve", 667, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, { "Adieresis", 667, NULL }, { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 556, NULL }, { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, { "ucircumflex", 556, NULL }, { "bracketleft", 278, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 222, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, { "umacron", 556, NULL }, { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, { "edieresis", 556, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 889, NULL }, { "asterisk", 389, NULL }, { "odieresis", 556, NULL }, { "Uacute", 722, NULL }, { "ugrave", 556, NULL }, { "nine", 556, NULL }, { "five", 556, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, { "Ccedilla", 722, NULL }, { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 1015, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, { "Euro", 556, NULL }, { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 556, NULL }, { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, { "Racute", 722, NULL }, { "partialdiff", 476, NULL }, { "uacute", 556, NULL }, { "braceleft", 334, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, { "scommaaccent", 500, NULL }, { "ccedilla", 500, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, { "scedilla", 500, NULL }, { "ogonek", 333, NULL }, { "ograve", 556, NULL }, { "racute", 333, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, { "radical", 453, NULL }, { "Aring", 667, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 537, NULL }, { "dcaron", 643, NULL }, { "Uogonek", 722, NULL }, { "two", 556, NULL }, { "summation", 600, NULL }, { "Igrave", 278, NULL }, { "Lacute", 556, NULL }, { "ocircumflex", 556, NULL }, { "oacute", 556, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 556, NULL }, { "tcaron", 317, NULL }, { "eogonek", 556, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 778, NULL }, { "asciicircum", 469, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, { "uogonek", 556, NULL }, { "bracketright", 278, NULL }, { "Iacute", 278, NULL }, { "ampersand", 667, NULL }, { "igrave", 278, NULL }, { "lacute", 222, NULL }, { "Ncaron", 722, NULL }, { "plus", 584, NULL }, { "uring", 556, NULL }, { "quotesinglbase", 222, NULL }, { "lcommaaccent", 222, NULL }, { "Yacute", 667, NULL }, { "ohungarumlaut", 556, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 333, NULL }, { "ncaron", 556, NULL }, { "florin", 556, NULL }, { "yacute", 500, NULL }, { "Rcommaaccent", 722, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 667, NULL }, { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, { "Amacron", 667, NULL }, { "seven", 556, NULL }, { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, { "notequal", 549, NULL }, { "Imacron", 278, NULL }, { "rcommaaccent", 333, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, { "cacute", 500, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 334, NULL }, { "quotedblright", 333, NULL }, { "amacron", 556, NULL }, { "sacute", 500, NULL }, { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, { "zdotaccent", 500, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 260, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 278, NULL }, { "period", 278, NULL }, { "Rcaron", 722, NULL }, { "Kcommaaccent", 667, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 260, NULL }, { "quoteleft", 222, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaBoldWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 389, NULL }, { "kcommaaccent", 556, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 333, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, { "Lcaron", 611, NULL }, { "ntilde", 611, NULL }, { "Aogonek", 722, NULL }, { "ncommaaccent", 611, NULL }, { "minus", 584, NULL }, { "Iogonek", 278, NULL }, { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, { "lcaron", 400, NULL }, { "A", 722, NULL }, { "B", 722, NULL }, { "C", 722, NULL }, { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, { "F", 611, NULL }, { "G", 778, NULL }, { "H", 722, NULL }, { "I", 278, NULL }, { "J", 556, NULL }, { "K", 722, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, { "omacron", 611, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, { "S", 667, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 556, NULL }, { "V", 667, NULL }, { "W", 944, NULL }, { "X", 667, NULL }, { "question", 611, NULL }, { "equal", 584, NULL }, { "Y", 667, NULL }, { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, { "Gcommaaccent", 778, NULL }, { "b", 611, NULL }, { "c", 556, NULL }, { "d", 611, NULL }, { "e", 556, NULL }, { "f", 333, NULL }, { "g", 611, NULL }, { "bullet", 350, NULL }, { "h", 611, NULL }, { "i", 278, NULL }, { "Oslash", 778, NULL }, { "dagger", 556, NULL }, { "j", 278, NULL }, { "k", 556, NULL }, { "l", 278, NULL }, { "m", 889, NULL }, { "n", 611, NULL }, { "tcommaaccent", 333, NULL }, { "o", 611, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 611, NULL }, { "q", 611, NULL }, { "uhungarumlaut", 611, NULL }, { "r", 389, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, { "s", 556, NULL }, { "OE", 1000, NULL }, { "t", 333, NULL }, { "divide", 584, NULL }, { "u", 611, NULL }, { "Ccaron", 722, NULL }, { "v", 556, NULL }, { "w", 778, NULL }, { "x", 556, NULL }, { "y", 556, NULL }, { "z", 500, NULL }, { "Gbreve", 778, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 278, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 474, NULL }, { "gcommaaccent", 611, NULL }, { "mu", 611, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 611, NULL }, { "lessequal", 549, NULL }, { "lozenge", 494, NULL }, { "parenright", 333, NULL }, { "ccaron", 556, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 611, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, { "nacute", 611, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 556, NULL }, { "AE", 1000, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 500, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 238, NULL }, { "eight", 556, NULL }, { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, { "Abreve", 722, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, { "Adieresis", 722, NULL }, { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 611, NULL }, { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, { "ucircumflex", 611, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 278, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, { "umacron", 611, NULL }, { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, { "edieresis", 556, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 889, NULL }, { "asterisk", 389, NULL }, { "odieresis", 611, NULL }, { "Uacute", 722, NULL }, { "ugrave", 611, NULL }, { "nine", 556, NULL }, { "five", 556, NULL }, { "udieresis", 611, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, { "Ccedilla", 722, NULL }, { "ydieresis", 556, NULL }, { "tilde", 333, NULL }, { "dbldaggerumlaut", 556, NULL }, { "at", 975, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, { "Euro", 556, NULL }, { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 611, NULL }, { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, { "Racute", 722, NULL }, { "partialdiff", 494, NULL }, { "uacute", 611, NULL }, { "braceleft", 389, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, { "scommaaccent", 556, NULL }, { "ccedilla", 556, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 611, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, { "scedilla", 556, NULL }, { "ogonek", 333, NULL }, { "ograve", 611, NULL }, { "racute", 389, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 667, NULL }, { "thorn", 611, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 556, NULL }, { "dcaron", 743, NULL }, { "Uogonek", 722, NULL }, { "two", 556, NULL }, { "summation", 600, NULL }, { "Igrave", 278, NULL }, { "Lacute", 611, NULL }, { "ocircumflex", 611, NULL }, { "oacute", 611, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 611, NULL }, { "tcaron", 389, NULL }, { "eogonek", 556, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 778, NULL }, { "asciicircum", 584, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, { "uogonek", 611, NULL }, { "bracketright", 333, NULL }, { "Iacute", 278, NULL }, { "ampersand", 722, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 722, NULL }, { "plus", 584, NULL }, { "uring", 611, NULL }, { "quotesinglbase", 278, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 667, NULL }, { "ohungarumlaut", 611, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, { "ncaron", 611, NULL }, { "florin", 556, NULL }, { "yacute", 556, NULL }, { "Rcommaaccent", 722, NULL }, { "fi", 611, NULL }, { "fl", 611, NULL }, { "Acircumflex", 722, NULL }, { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, { "Amacron", 722, NULL }, { "seven", 556, NULL }, { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, { "notequal", 549, NULL }, { "Imacron", 278, NULL }, { "rcommaaccent", 389, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, { "cacute", 556, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 389, NULL }, { "quotedblright", 500, NULL }, { "amacron", 556, NULL }, { "sacute", 556, NULL }, { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, { "zdotaccent", 500, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 280, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 278, NULL }, { "Rcaron", 722, NULL }, { "Kcommaaccent", 722, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 280, NULL }, { "quoteleft", 278, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 389, NULL }, { "kcommaaccent", 556, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 333, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, { "Lcaron", 611, NULL }, { "ntilde", 611, NULL }, { "Aogonek", 722, NULL }, { "ncommaaccent", 611, NULL }, { "minus", 584, NULL }, { "Iogonek", 278, NULL }, { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, { "lcaron", 400, NULL }, { "A", 722, NULL }, { "B", 722, NULL }, { "C", 722, NULL }, { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, { "F", 611, NULL }, { "G", 778, NULL }, { "H", 722, NULL }, { "I", 278, NULL }, { "J", 556, NULL }, { "K", 722, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, { "omacron", 611, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, { "S", 667, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 556, NULL }, { "V", 667, NULL }, { "W", 944, NULL }, { "X", 667, NULL }, { "question", 611, NULL }, { "equal", 584, NULL }, { "Y", 667, NULL }, { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, { "Gcommaaccent", 778, NULL }, { "b", 611, NULL }, { "c", 556, NULL }, { "d", 611, NULL }, { "e", 556, NULL }, { "f", 333, NULL }, { "g", 611, NULL }, { "bullet", 350, NULL }, { "h", 611, NULL }, { "i", 278, NULL }, { "Oslash", 778, NULL }, { "dagger", 556, NULL }, { "j", 278, NULL }, { "k", 556, NULL }, { "l", 278, NULL }, { "m", 889, NULL }, { "n", 611, NULL }, { "tcommaaccent", 333, NULL }, { "o", 611, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 611, NULL }, { "q", 611, NULL }, { "uhungarumlaut", 611, NULL }, { "r", 389, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, { "s", 556, NULL }, { "OE", 1000, NULL }, { "t", 333, NULL }, { "divide", 584, NULL }, { "u", 611, NULL }, { "Ccaron", 722, NULL }, { "v", 556, NULL }, { "w", 778, NULL }, { "x", 556, NULL }, { "y", 556, NULL }, { "z", 500, NULL }, { "Gbreve", 778, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 278, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 474, NULL }, { "gcommaaccent", 611, NULL }, { "mu", 611, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 611, NULL }, { "lessequal", 549, NULL }, { "lozenge", 494, NULL }, { "parenright", 333, NULL }, { "ccaron", 556, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 611, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, { "nacute", 611, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 556, NULL }, { "AE", 1000, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 500, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 238, NULL }, { "eight", 556, NULL }, { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, { "Abreve", 722, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, { "Adieresis", 722, NULL }, { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 611, NULL }, { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, { "ucircumflex", 611, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 278, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, { "umacron", 611, NULL }, { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, { "edieresis", 556, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 889, NULL }, { "asterisk", 389, NULL }, { "odieresis", 611, NULL }, { "Uacute", 722, NULL }, { "ugrave", 611, NULL }, { "nine", 556, NULL }, { "five", 556, NULL }, { "udieresis", 611, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, { "Ccedilla", 722, NULL }, { "ydieresis", 556, NULL }, { "tilde", 333, NULL }, { "at", 975, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, { "Euro", 556, NULL }, { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 611, NULL }, { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, { "Racute", 722, NULL }, { "partialdiff", 494, NULL }, { "uacute", 611, NULL }, { "braceleft", 389, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, { "scommaaccent", 556, NULL }, { "ccedilla", 556, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 611, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, { "scedilla", 556, NULL }, { "ogonek", 333, NULL }, { "ograve", 611, NULL }, { "racute", 389, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 667, NULL }, { "thorn", 611, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 556, NULL }, { "dcaron", 743, NULL }, { "Uogonek", 722, NULL }, { "two", 556, NULL }, { "summation", 600, NULL }, { "Igrave", 278, NULL }, { "Lacute", 611, NULL }, { "ocircumflex", 611, NULL }, { "oacute", 611, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 611, NULL }, { "tcaron", 389, NULL }, { "eogonek", 556, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 778, NULL }, { "asciicircum", 584, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, { "uogonek", 611, NULL }, { "bracketright", 333, NULL }, { "Iacute", 278, NULL }, { "ampersand", 722, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 722, NULL }, { "plus", 584, NULL }, { "uring", 611, NULL }, { "quotesinglbase", 278, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 667, NULL }, { "ohungarumlaut", 611, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, { "ncaron", 611, NULL }, { "florin", 556, NULL }, { "yacute", 556, NULL }, { "Rcommaaccent", 722, NULL }, { "fi", 611, NULL }, { "fl", 611, NULL }, { "Acircumflex", 722, NULL }, { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, { "Amacron", 722, NULL }, { "seven", 556, NULL }, { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, { "notequal", 549, NULL }, { "Imacron", 278, NULL }, { "rcommaaccent", 389, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, { "cacute", 556, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 389, NULL }, { "quotedblright", 500, NULL }, { "amacron", 556, NULL }, { "sacute", 556, NULL }, { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, { "zdotaccent", 500, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 280, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 278, NULL }, { "Rcaron", 722, NULL }, { "Kcommaaccent", 722, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 280, NULL }, { "quoteleft", 278, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth helveticaObliqueWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 333, NULL }, { "kcommaaccent", 500, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 278, NULL }, { "cedilla", 333, NULL }, { "plusminus", 584, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 556, NULL }, { "asciitilde", 584, NULL }, { "colon", 278, NULL }, { "onehalf", 834, NULL }, { "dollar", 556, NULL }, { "Lcaron", 556, NULL }, { "ntilde", 556, NULL }, { "Aogonek", 667, NULL }, { "ncommaaccent", 556, NULL }, { "minus", 584, NULL }, { "Iogonek", 278, NULL }, { "zacute", 500, NULL }, { "yen", 556, NULL }, { "space", 278, NULL }, { "Omacron", 778, NULL }, { "questiondown", 611, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 556, NULL }, { "numbersign", 556, NULL }, { "lcaron", 299, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, { "aogonek", 556, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 834, NULL }, { "F", 611, NULL }, { "G", 778, NULL }, { "H", 722, NULL }, { "I", 278, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, { "iogonek", 222, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 278, NULL }, { "M", 833, NULL }, { "N", 722, NULL }, { "omacron", 556, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 778, NULL }, { "P", 667, NULL }, { "Q", 778, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, { "S", 667, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 556, NULL }, { "V", 667, NULL }, { "W", 944, NULL }, { "X", 667, NULL }, { "question", 556, NULL }, { "equal", 584, NULL }, { "Y", 667, NULL }, { "Z", 611, NULL }, { "four", 556, NULL }, { "a", 556, NULL }, { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 500, NULL }, { "d", 556, NULL }, { "e", 556, NULL }, { "f", 278, NULL }, { "g", 556, NULL }, { "bullet", 350, NULL }, { "h", 556, NULL }, { "i", 222, NULL }, { "Oslash", 778, NULL }, { "dagger", 556, NULL }, { "j", 222, NULL }, { "k", 500, NULL }, { "l", 222, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, { "tcommaaccent", 278, NULL }, { "o", 556, NULL }, { "ordfeminine", 370, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, { "uhungarumlaut", 556, NULL }, { "r", 333, NULL }, { "twosuperior", 333, NULL }, { "aacute", 556, NULL }, { "s", 500, NULL }, { "OE", 1000, NULL }, { "t", 278, NULL }, { "divide", 584, NULL }, { "u", 556, NULL }, { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 500, NULL }, { "Gbreve", 778, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 278, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 355, NULL }, { "gcommaaccent", 556, NULL }, { "mu", 556, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 667, NULL }, { "Lslash", 556, NULL }, { "semicolon", 278, NULL }, { "oslash", 611, NULL }, { "lessequal", 549, NULL }, { "lozenge", 471, NULL }, { "parenright", 333, NULL }, { "ccaron", 500, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 556, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 556, NULL }, { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 500, NULL }, { "AE", 1000, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 222, NULL }, { "quotedblleft", 333, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 191, NULL }, { "eight", 556, NULL }, { "exclamdown", 333, NULL }, { "endash", 556, NULL }, { "oe", 944, NULL }, { "Abreve", 667, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 556, NULL }, { "Adieresis", 667, NULL }, { "copyright", 737, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 556, NULL }, { "Idieresis", 278, NULL }, { "parenleft", 333, NULL }, { "one", 556, NULL }, { "emacron", 556, NULL }, { "Odieresis", 778, NULL }, { "ucircumflex", 556, NULL }, { "bracketleft", 278, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 222, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 667, NULL }, { "umacron", 556, NULL }, { "abreve", 556, NULL }, { "Eacute", 667, NULL }, { "adieresis", 556, NULL }, { "egrave", 556, NULL }, { "edieresis", 556, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 889, NULL }, { "asterisk", 389, NULL }, { "odieresis", 556, NULL }, { "Uacute", 722, NULL }, { "ugrave", 556, NULL }, { "nine", 556, NULL }, { "five", 556, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 667, NULL }, { "threequarters", 834, NULL }, { "guillemotright", 556, NULL }, { "Ccedilla", 722, NULL }, { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 1015, NULL }, { "eacute", 556, NULL }, { "underscore", 556, NULL }, { "Euro", 556, NULL }, { "Dcroat", 722, NULL }, { "multiply", 584, NULL }, { "zero", 556, NULL }, { "eth", 556, NULL }, { "Scedilla", 667, NULL }, { "Ograve", 778, NULL }, { "Racute", 722, NULL }, { "partialdiff", 476, NULL }, { "uacute", 556, NULL }, { "braceleft", 334, NULL }, { "Thorn", 667, NULL }, { "zcaron", 500, NULL }, { "scommaaccent", 500, NULL }, { "ccedilla", 500, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, { "scedilla", 500, NULL }, { "ogonek", 333, NULL }, { "ograve", 556, NULL }, { "racute", 333, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 737, NULL }, { "radical", 453, NULL }, { "Aring", 667, NULL }, { "percent", 889, NULL }, { "six", 556, NULL }, { "paragraph", 537, NULL }, { "dcaron", 643, NULL }, { "Uogonek", 722, NULL }, { "two", 556, NULL }, { "summation", 600, NULL }, { "Igrave", 278, NULL }, { "Lacute", 556, NULL }, { "ocircumflex", 556, NULL }, { "oacute", 556, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 556, NULL }, { "tcaron", 317, NULL }, { "eogonek", 556, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 778, NULL }, { "asciicircum", 469, NULL }, { "aring", 556, NULL }, { "grave", 333, NULL }, { "uogonek", 556, NULL }, { "bracketright", 278, NULL }, { "Iacute", 278, NULL }, { "ampersand", 667, NULL }, { "igrave", 278, NULL }, { "lacute", 222, NULL }, { "Ncaron", 722, NULL }, { "plus", 584, NULL }, { "uring", 556, NULL }, { "quotesinglbase", 222, NULL }, { "lcommaaccent", 222, NULL }, { "Yacute", 667, NULL }, { "ohungarumlaut", 556, NULL }, { "threesuperior", 333, NULL }, { "acute", 333, NULL }, { "section", 556, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 333, NULL }, { "ncaron", 556, NULL }, { "florin", 556, NULL }, { "yacute", 500, NULL }, { "Rcommaaccent", 722, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 667, NULL }, { "Cacute", 722, NULL }, { "Icircumflex", 278, NULL }, { "guillemotleft", 556, NULL }, { "germandbls", 611, NULL }, { "Amacron", 667, NULL }, { "seven", 556, NULL }, { "Sacute", 667, NULL }, { "ordmasculine", 365, NULL }, { "dotlessi", 278, NULL }, { "sterling", 556, NULL }, { "notequal", 549, NULL }, { "Imacron", 278, NULL }, { "rcommaaccent", 333, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 556, NULL }, { "cacute", 500, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 334, NULL }, { "quotedblright", 333, NULL }, { "amacron", 556, NULL }, { "sacute", 500, NULL }, { "imacron", 278, NULL }, { "cent", 556, NULL }, { "currency", 556, NULL }, { "logicalnot", 584, NULL }, { "zdotaccent", 500, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 260, NULL }, { "fraction", 167, NULL }, { "less", 584, NULL }, { "ecaron", 556, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 278, NULL }, { "period", 278, NULL }, { "Rcaron", 722, NULL }, { "Kcommaaccent", 667, NULL }, { "greater", 584, NULL }, { "atilde", 556, NULL }, { "brokenbar", 260, NULL }, { "quoteleft", 222, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 333, NULL } }; static BuiltinFontWidth symbolWidthsTab[] = { { "bracketleftex", 384, NULL }, { "alpha", 631, NULL }, { "union", 768, NULL }, { "infinity", 713, NULL }, { "comma", 250, NULL }, { "copyrightsans", 790, NULL }, { "plusminus", 549, NULL }, { "arrowup", 603, NULL }, { "apple", 790, NULL }, { "parenleftbt", 384, NULL }, { "notelement", 713, NULL }, { "colon", 278, NULL }, { "beta", 549, NULL }, { "braceleftbt", 494, NULL }, { "Lambda", 686, NULL }, { "Phi", 763, NULL }, { "minus", 549, NULL }, { "space", 250, NULL }, { "Sigma", 592, NULL }, { "approxequal", 549, NULL }, { "minute", 247, NULL }, { "circleplus", 768, NULL }, { "Omicron", 722, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, { "lambda", 549, NULL }, { "phi", 521, NULL }, { "aleph", 823, NULL }, { "Tau", 611, NULL }, { "spade", 753, NULL }, { "logicaland", 603, NULL }, { "sigma", 603, NULL }, { "propersuperset", 713, NULL }, { "omicron", 549, NULL }, { "question", 444, NULL }, { "equal", 549, NULL }, { "Epsilon", 611, NULL }, { "emptyset", 823, NULL }, { "diamond", 753, NULL }, { "four", 500, NULL }, { "Mu", 889, NULL }, { "parenlefttp", 384, NULL }, { "club", 753, NULL }, { "bullet", 460, NULL }, { "Omega", 768, NULL }, { "tau", 439, NULL }, { "Upsilon", 690, NULL }, { "bracelefttp", 494, NULL }, { "heart", 753, NULL }, { "divide", 549, NULL }, { "epsilon", 439, NULL }, { "logicalor", 603, NULL }, { "parenleftex", 384, NULL }, { "greaterequal", 549, NULL }, { "mu", 576, NULL }, { "Nu", 722, NULL }, { "therefore", 863, NULL }, { "notsubset", 713, NULL }, { "omega", 686, NULL }, { "semicolon", 278, NULL }, { "element", 713, NULL }, { "upsilon", 576, NULL }, { "existential", 549, NULL }, { "integralbt", 686, NULL }, { "lessequal", 549, NULL }, { "phi1", 603, NULL }, { "lozenge", 494, NULL }, { "trademarkserif", 890, NULL }, { "parenright", 333, NULL }, { "reflexsuperset", 713, NULL }, { "sigma1", 439, NULL }, { "nu", 521, NULL }, { "Gamma", 603, NULL }, { "angleright", 329, NULL }, { "ellipsis", 1000, NULL }, { "Rho", 556, NULL }, { "parenrightbt", 384, NULL }, { "radicalex", 500, NULL }, { "eight", 500, NULL }, { "angleleft", 329, NULL }, { "arrowdbldown", 603, NULL }, { "congruent", 549, NULL }, { "Theta", 741, NULL }, { "intersection", 768, NULL }, { "Pi", 768, NULL }, { "slash", 278, NULL }, { "registerserif", 790, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, { "gamma", 411, NULL }, { "bracketleft", 333, NULL }, { "rho", 549, NULL }, { "circlemultiply", 768, NULL }, { "Chi", 722, NULL }, { "theta", 521, NULL }, { "pi", 549, NULL }, { "integraltp", 686, NULL }, { "Eta", 722, NULL }, { "product", 823, NULL }, { "nine", 500, NULL }, { "five", 500, NULL }, { "propersubset", 713, NULL }, { "bracketrightbt", 384, NULL }, { "trademarksans", 786, NULL }, { "dotmath", 250, NULL }, { "integralex", 686, NULL }, { "chi", 549, NULL }, { "parenrighttp", 384, NULL }, { "eta", 603, NULL }, { "underscore", 500, NULL }, { "Euro", 750, NULL }, { "multiply", 549, NULL }, { "zero", 500, NULL }, { "partialdiff", 494, NULL }, { "angle", 768, NULL }, { "arrowdblleft", 987, NULL }, { "braceleft", 480, NULL }, { "parenrightex", 384, NULL }, { "Rfraktur", 795, NULL }, { "Zeta", 611, NULL }, { "braceex", 494, NULL }, { "arrowdblup", 603, NULL }, { "arrowdown", 603, NULL }, { "Ifraktur", 686, NULL }, { "degree", 400, NULL }, { "Iota", 333, NULL }, { "perpendicular", 658, NULL }, { "radical", 549, NULL }, { "asteriskmath", 500, NULL }, { "percent", 833, NULL }, { "zeta", 494, NULL }, { "six", 500, NULL }, { "two", 500, NULL }, { "weierstrass", 987, NULL }, { "summation", 713, NULL }, { "bracketrighttp", 384, NULL }, { "carriagereturn", 658, NULL }, { "suchthat", 439, NULL }, { "arrowvertex", 603, NULL }, { "Delta", 612, NULL }, { "iota", 329, NULL }, { "arrowhorizex", 1000, NULL }, { "bracketrightex", 384, NULL }, { "bracketright", 333, NULL }, { "ampersand", 778, NULL }, { "plus", 549, NULL }, { "proportional", 713, NULL }, { "delta", 494, NULL }, { "copyrightserif", 790, NULL }, { "bracerightmid", 494, NULL }, { "arrowleft", 987, NULL }, { "second", 411, NULL }, { "arrowdblboth", 1042, NULL }, { "florin", 500, NULL }, { "Psi", 795, NULL }, { "bracerightbt", 494, NULL }, { "bracketleftbt", 384, NULL }, { "seven", 500, NULL }, { "braceleftmid", 494, NULL }, { "notequal", 549, NULL }, { "psi", 686, NULL }, { "equivalence", 549, NULL }, { "universal", 713, NULL }, { "arrowdblright", 987, NULL }, { "braceright", 480, NULL }, { "reflexsubset", 713, NULL }, { "Xi", 645, NULL }, { "theta1", 631, NULL }, { "logicalnot", 713, NULL }, { "Kappa", 722, NULL }, { "similar", 549, NULL }, { "bar", 200, NULL }, { "fraction", 167, NULL }, { "less", 549, NULL }, { "registersans", 790, NULL }, { "omega1", 713, NULL }, { "exclam", 333, NULL }, { "Upsilon1", 620, NULL }, { "bracerighttp", 494, NULL }, { "xi", 493, NULL }, { "period", 250, NULL }, { "Alpha", 722, NULL }, { "arrowright", 987, NULL }, { "greater", 549, NULL }, { "bracketlefttp", 384, NULL }, { "kappa", 549, NULL }, { "gradient", 713, NULL }, { "integral", 274, NULL }, { "arrowboth", 1042, NULL }, { "Beta", 667, NULL } }; static BuiltinFontWidth timesBoldWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 444, NULL }, { "kcommaaccent", 556, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 667, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 570, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 444, NULL }, { "asciitilde", 520, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, { "Lcaron", 667, NULL }, { "ntilde", 556, NULL }, { "Aogonek", 722, NULL }, { "ncommaaccent", 556, NULL }, { "minus", 570, NULL }, { "Iogonek", 389, NULL }, { "zacute", 444, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, { "Omacron", 778, NULL }, { "questiondown", 500, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, { "lcaron", 394, NULL }, { "A", 722, NULL }, { "B", 667, NULL }, { "C", 722, NULL }, { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 750, NULL }, { "F", 611, NULL }, { "G", 778, NULL }, { "H", 778, NULL }, { "I", 389, NULL }, { "J", 500, NULL }, { "K", 778, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 667, NULL }, { "periodcentered", 250, NULL }, { "M", 944, NULL }, { "N", 722, NULL }, { "omacron", 500, NULL }, { "Tcommaaccent", 667, NULL }, { "O", 778, NULL }, { "P", 611, NULL }, { "Q", 778, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 722, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, { "S", 556, NULL }, { "T", 667, NULL }, { "U", 722, NULL }, { "agrave", 500, NULL }, { "V", 722, NULL }, { "W", 1000, NULL }, { "X", 722, NULL }, { "question", 500, NULL }, { "equal", 570, NULL }, { "Y", 722, NULL }, { "Z", 667, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, { "Gcommaaccent", 778, NULL }, { "b", 556, NULL }, { "c", 444, NULL }, { "d", 556, NULL }, { "e", 444, NULL }, { "f", 333, NULL }, { "g", 500, NULL }, { "bullet", 350, NULL }, { "h", 556, NULL }, { "i", 278, NULL }, { "Oslash", 778, NULL }, { "dagger", 500, NULL }, { "j", 333, NULL }, { "k", 556, NULL }, { "l", 278, NULL }, { "m", 833, NULL }, { "n", 556, NULL }, { "tcommaaccent", 333, NULL }, { "o", 500, NULL }, { "ordfeminine", 300, NULL }, { "ring", 333, NULL }, { "p", 556, NULL }, { "q", 556, NULL }, { "uhungarumlaut", 556, NULL }, { "r", 444, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, { "s", 389, NULL }, { "OE", 1000, NULL }, { "t", 333, NULL }, { "divide", 570, NULL }, { "u", 556, NULL }, { "Ccaron", 722, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 444, NULL }, { "Gbreve", 778, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 389, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 555, NULL }, { "gcommaaccent", 500, NULL }, { "mu", 556, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 667, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, { "lessequal", 549, NULL }, { "lozenge", 494, NULL }, { "parenright", 333, NULL }, { "ccaron", 444, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 500, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 500, NULL }, { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 778, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 1000, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 500, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 278, NULL }, { "eight", 500, NULL }, { "exclamdown", 333, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, { "Abreve", 722, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, { "Adieresis", 722, NULL }, { "copyright", 747, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 500, NULL }, { "Idieresis", 389, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, { "emacron", 444, NULL }, { "Odieresis", 778, NULL }, { "ucircumflex", 556, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 722, NULL }, { "umacron", 556, NULL }, { "abreve", 500, NULL }, { "Eacute", 667, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, { "edieresis", 444, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 722, NULL }, { "asterisk", 500, NULL }, { "odieresis", 500, NULL }, { "Uacute", 722, NULL }, { "ugrave", 556, NULL }, { "nine", 500, NULL }, { "five", 500, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 667, NULL }, { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, { "Ccedilla", 722, NULL }, { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 930, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, { "Euro", 500, NULL }, { "Dcroat", 722, NULL }, { "multiply", 570, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, { "Scedilla", 556, NULL }, { "Ograve", 778, NULL }, { "Racute", 722, NULL }, { "partialdiff", 494, NULL }, { "uacute", 556, NULL }, { "braceleft", 394, NULL }, { "Thorn", 611, NULL }, { "zcaron", 444, NULL }, { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 556, NULL }, { "Ocircumflex", 778, NULL }, { "Oacute", 778, NULL }, { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, { "racute", 444, NULL }, { "Tcaron", 667, NULL }, { "Eogonek", 667, NULL }, { "thorn", 556, NULL }, { "degree", 400, NULL }, { "registered", 747, NULL }, { "radical", 549, NULL }, { "Aring", 722, NULL }, { "percent", 1000, NULL }, { "six", 500, NULL }, { "paragraph", 540, NULL }, { "dcaron", 672, NULL }, { "Uogonek", 722, NULL }, { "two", 500, NULL }, { "summation", 600, NULL }, { "Igrave", 389, NULL }, { "Lacute", 667, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 667, NULL }, { "tcaron", 416, NULL }, { "eogonek", 444, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 778, NULL }, { "asciicircum", 581, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, { "uogonek", 556, NULL }, { "bracketright", 333, NULL }, { "Iacute", 389, NULL }, { "ampersand", 833, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 722, NULL }, { "plus", 570, NULL }, { "uring", 556, NULL }, { "quotesinglbase", 333, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 722, NULL }, { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, { "ncaron", 556, NULL }, { "florin", 500, NULL }, { "yacute", 500, NULL }, { "Rcommaaccent", 722, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 722, NULL }, { "Cacute", 722, NULL }, { "Icircumflex", 389, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 556, NULL }, { "Amacron", 722, NULL }, { "seven", 500, NULL }, { "Sacute", 556, NULL }, { "ordmasculine", 330, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, { "notequal", 549, NULL }, { "Imacron", 389, NULL }, { "rcommaaccent", 444, NULL }, { "Zdotaccent", 667, NULL }, { "acircumflex", 500, NULL }, { "cacute", 444, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 394, NULL }, { "quotedblright", 500, NULL }, { "amacron", 500, NULL }, { "sacute", 389, NULL }, { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 570, NULL }, { "zdotaccent", 444, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 220, NULL }, { "fraction", 167, NULL }, { "less", 570, NULL }, { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, { "Rcaron", 722, NULL }, { "Kcommaaccent", 778, NULL }, { "greater", 570, NULL }, { "atilde", 500, NULL }, { "brokenbar", 220, NULL }, { "quoteleft", 333, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesBoldItalicWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 389, NULL }, { "kcommaaccent", 500, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 570, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 444, NULL }, { "asciitilde", 570, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, { "Lcaron", 611, NULL }, { "ntilde", 556, NULL }, { "Aogonek", 667, NULL }, { "ncommaaccent", 556, NULL }, { "minus", 606, NULL }, { "Iogonek", 389, NULL }, { "zacute", 389, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, { "Omacron", 722, NULL }, { "questiondown", 500, NULL }, { "emdash", 1000, NULL }, { "Agrave", 667, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, { "lcaron", 382, NULL }, { "A", 667, NULL }, { "B", 667, NULL }, { "C", 667, NULL }, { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 667, NULL }, { "onequarter", 750, NULL }, { "F", 667, NULL }, { "G", 722, NULL }, { "H", 778, NULL }, { "I", 389, NULL }, { "J", 500, NULL }, { "K", 667, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 250, NULL }, { "M", 889, NULL }, { "N", 722, NULL }, { "omacron", 500, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 722, NULL }, { "P", 611, NULL }, { "Q", 722, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 667, NULL }, { "Aacute", 667, NULL }, { "caron", 333, NULL }, { "S", 556, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 500, NULL }, { "V", 667, NULL }, { "W", 889, NULL }, { "X", 667, NULL }, { "question", 500, NULL }, { "equal", 570, NULL }, { "Y", 611, NULL }, { "Z", 611, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, { "e", 444, NULL }, { "f", 333, NULL }, { "g", 500, NULL }, { "bullet", 350, NULL }, { "h", 556, NULL }, { "i", 278, NULL }, { "Oslash", 722, NULL }, { "dagger", 500, NULL }, { "j", 278, NULL }, { "k", 500, NULL }, { "l", 278, NULL }, { "m", 778, NULL }, { "n", 556, NULL }, { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 266, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, { "uhungarumlaut", 556, NULL }, { "r", 389, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, { "s", 389, NULL }, { "OE", 944, NULL }, { "t", 278, NULL }, { "divide", 570, NULL }, { "u", 556, NULL }, { "Ccaron", 667, NULL }, { "v", 444, NULL }, { "w", 667, NULL }, { "x", 500, NULL }, { "y", 444, NULL }, { "z", 389, NULL }, { "Gbreve", 722, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 389, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 555, NULL }, { "gcommaaccent", 500, NULL }, { "mu", 576, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 611, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, { "lessequal", 549, NULL }, { "lozenge", 494, NULL }, { "parenright", 333, NULL }, { "ccaron", 444, NULL }, { "Ecircumflex", 667, NULL }, { "gbreve", 500, NULL }, { "trademark", 1000, NULL }, { "daggerdbl", 500, NULL }, { "nacute", 556, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, { "Emacron", 667, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 944, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 500, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 278, NULL }, { "eight", 500, NULL }, { "exclamdown", 389, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, { "Abreve", 667, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, { "Adieresis", 667, NULL }, { "copyright", 747, NULL }, { "Egrave", 667, NULL }, { "slash", 278, NULL }, { "Edieresis", 667, NULL }, { "otilde", 500, NULL }, { "Idieresis", 389, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, { "ucircumflex", 556, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 611, NULL }, { "umacron", 556, NULL }, { "abreve", 500, NULL }, { "Eacute", 667, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, { "edieresis", 444, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 722, NULL }, { "asterisk", 500, NULL }, { "odieresis", 500, NULL }, { "Uacute", 722, NULL }, { "ugrave", 556, NULL }, { "nine", 500, NULL }, { "five", 500, NULL }, { "udieresis", 556, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, { "Ccedilla", 667, NULL }, { "ydieresis", 444, NULL }, { "tilde", 333, NULL }, { "at", 832, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, { "Euro", 500, NULL }, { "Dcroat", 722, NULL }, { "multiply", 570, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, { "Scedilla", 556, NULL }, { "Ograve", 722, NULL }, { "Racute", 667, NULL }, { "partialdiff", 494, NULL }, { "uacute", 556, NULL }, { "braceleft", 348, NULL }, { "Thorn", 611, NULL }, { "zcaron", 389, NULL }, { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, { "racute", 389, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 667, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 747, NULL }, { "radical", 549, NULL }, { "Aring", 667, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 500, NULL }, { "dcaron", 608, NULL }, { "Uogonek", 722, NULL }, { "two", 500, NULL }, { "summation", 600, NULL }, { "Igrave", 389, NULL }, { "Lacute", 611, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 611, NULL }, { "tcaron", 366, NULL }, { "eogonek", 444, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 722, NULL }, { "asciicircum", 570, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, { "uogonek", 556, NULL }, { "bracketright", 333, NULL }, { "Iacute", 389, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 722, NULL }, { "plus", 570, NULL }, { "uring", 556, NULL }, { "quotesinglbase", 333, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 611, NULL }, { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 500, NULL }, { "ncaron", 556, NULL }, { "florin", 500, NULL }, { "yacute", 444, NULL }, { "Rcommaaccent", 667, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 667, NULL }, { "Cacute", 667, NULL }, { "Icircumflex", 389, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, { "Amacron", 667, NULL }, { "seven", 500, NULL }, { "Sacute", 556, NULL }, { "ordmasculine", 300, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, { "notequal", 549, NULL }, { "Imacron", 389, NULL }, { "rcommaaccent", 389, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 500, NULL }, { "cacute", 444, NULL }, { "Ecaron", 667, NULL }, { "icircumflex", 278, NULL }, { "braceright", 348, NULL }, { "quotedblright", 500, NULL }, { "amacron", 500, NULL }, { "sacute", 389, NULL }, { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 606, NULL }, { "zdotaccent", 389, NULL }, { "Atilde", 667, NULL }, { "breve", 333, NULL }, { "bar", 220, NULL }, { "fraction", 167, NULL }, { "less", 570, NULL }, { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 389, NULL }, { "period", 250, NULL }, { "Rcaron", 667, NULL }, { "Kcommaaccent", 667, NULL }, { "greater", 570, NULL }, { "atilde", 500, NULL }, { "brokenbar", 220, NULL }, { "quoteleft", 333, NULL }, { "Edotaccent", 667, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesItalicWidthsTab[] = { { "Ntilde", 667, NULL }, { "rcaron", 389, NULL }, { "kcommaaccent", 444, NULL }, { "Ncommaaccent", 667, NULL }, { "Zacute", 556, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 675, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 444, NULL }, { "asciitilde", 541, NULL }, { "colon", 333, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, { "Lcaron", 611, NULL }, { "ntilde", 500, NULL }, { "Aogonek", 611, NULL }, { "ncommaaccent", 500, NULL }, { "minus", 675, NULL }, { "Iogonek", 333, NULL }, { "zacute", 389, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, { "Omacron", 722, NULL }, { "questiondown", 500, NULL }, { "emdash", 889, NULL }, { "Agrave", 611, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, { "lcaron", 300, NULL }, { "A", 611, NULL }, { "B", 611, NULL }, { "C", 667, NULL }, { "aogonek", 500, NULL }, { "D", 722, NULL }, { "E", 611, NULL }, { "onequarter", 750, NULL }, { "F", 611, NULL }, { "G", 722, NULL }, { "H", 722, NULL }, { "I", 333, NULL }, { "J", 444, NULL }, { "K", 667, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 556, NULL }, { "periodcentered", 250, NULL }, { "M", 833, NULL }, { "N", 667, NULL }, { "omacron", 500, NULL }, { "Tcommaaccent", 556, NULL }, { "O", 722, NULL }, { "P", 611, NULL }, { "Q", 722, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 611, NULL }, { "Aacute", 611, NULL }, { "caron", 333, NULL }, { "S", 500, NULL }, { "T", 556, NULL }, { "U", 722, NULL }, { "agrave", 500, NULL }, { "V", 611, NULL }, { "W", 833, NULL }, { "X", 611, NULL }, { "question", 500, NULL }, { "equal", 675, NULL }, { "Y", 556, NULL }, { "Z", 556, NULL }, { "four", 500, NULL }, { "a", 500, NULL }, { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, { "e", 444, NULL }, { "f", 278, NULL }, { "g", 500, NULL }, { "bullet", 350, NULL }, { "h", 500, NULL }, { "i", 278, NULL }, { "Oslash", 722, NULL }, { "dagger", 500, NULL }, { "j", 278, NULL }, { "k", 444, NULL }, { "l", 278, NULL }, { "m", 722, NULL }, { "n", 500, NULL }, { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 276, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, { "uhungarumlaut", 500, NULL }, { "r", 389, NULL }, { "twosuperior", 300, NULL }, { "aacute", 500, NULL }, { "s", 389, NULL }, { "OE", 944, NULL }, { "t", 278, NULL }, { "divide", 675, NULL }, { "u", 500, NULL }, { "Ccaron", 667, NULL }, { "v", 444, NULL }, { "w", 667, NULL }, { "x", 444, NULL }, { "y", 444, NULL }, { "z", 389, NULL }, { "Gbreve", 722, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 333, NULL }, { "Nacute", 667, NULL }, { "quotedbl", 420, NULL }, { "gcommaaccent", 500, NULL }, { "mu", 500, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 500, NULL }, { "Lslash", 556, NULL }, { "semicolon", 333, NULL }, { "oslash", 500, NULL }, { "lessequal", 549, NULL }, { "lozenge", 471, NULL }, { "parenright", 333, NULL }, { "ccaron", 444, NULL }, { "Ecircumflex", 611, NULL }, { "gbreve", 500, NULL }, { "trademark", 980, NULL }, { "daggerdbl", 500, NULL }, { "nacute", 500, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, { "Emacron", 611, NULL }, { "ellipsis", 889, NULL }, { "scaron", 389, NULL }, { "AE", 889, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 556, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 214, NULL }, { "eight", 500, NULL }, { "exclamdown", 389, NULL }, { "endash", 500, NULL }, { "oe", 667, NULL }, { "Abreve", 611, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, { "Adieresis", 611, NULL }, { "copyright", 760, NULL }, { "Egrave", 611, NULL }, { "slash", 278, NULL }, { "Edieresis", 611, NULL }, { "otilde", 500, NULL }, { "Idieresis", 333, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, { "ucircumflex", 500, NULL }, { "bracketleft", 389, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 556, NULL }, { "umacron", 500, NULL }, { "abreve", 500, NULL }, { "Eacute", 611, NULL }, { "adieresis", 500, NULL }, { "egrave", 444, NULL }, { "edieresis", 444, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 667, NULL }, { "asterisk", 500, NULL }, { "odieresis", 500, NULL }, { "Uacute", 722, NULL }, { "ugrave", 500, NULL }, { "nine", 500, NULL }, { "five", 500, NULL }, { "udieresis", 500, NULL }, { "Zcaron", 556, NULL }, { "Scommaaccent", 500, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, { "Ccedilla", 667, NULL }, { "ydieresis", 444, NULL }, { "tilde", 333, NULL }, { "at", 920, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, { "Euro", 500, NULL }, { "Dcroat", 722, NULL }, { "multiply", 675, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, { "Scedilla", 500, NULL }, { "Ograve", 722, NULL }, { "Racute", 611, NULL }, { "partialdiff", 476, NULL }, { "uacute", 500, NULL }, { "braceleft", 400, NULL }, { "Thorn", 611, NULL }, { "zcaron", 389, NULL }, { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, { "racute", 389, NULL }, { "Tcaron", 556, NULL }, { "Eogonek", 611, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 760, NULL }, { "radical", 453, NULL }, { "Aring", 611, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 523, NULL }, { "dcaron", 544, NULL }, { "Uogonek", 722, NULL }, { "two", 500, NULL }, { "summation", 600, NULL }, { "Igrave", 333, NULL }, { "Lacute", 556, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 556, NULL }, { "tcaron", 300, NULL }, { "eogonek", 444, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 722, NULL }, { "asciicircum", 422, NULL }, { "aring", 500, NULL }, { "grave", 333, NULL }, { "uogonek", 500, NULL }, { "bracketright", 389, NULL }, { "Iacute", 333, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 667, NULL }, { "plus", 675, NULL }, { "uring", 500, NULL }, { "quotesinglbase", 333, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 556, NULL }, { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 556, NULL }, { "ncaron", 500, NULL }, { "florin", 500, NULL }, { "yacute", 444, NULL }, { "Rcommaaccent", 611, NULL }, { "fi", 500, NULL }, { "fl", 500, NULL }, { "Acircumflex", 611, NULL }, { "Cacute", 667, NULL }, { "Icircumflex", 333, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, { "Amacron", 611, NULL }, { "seven", 500, NULL }, { "Sacute", 500, NULL }, { "ordmasculine", 310, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, { "notequal", 549, NULL }, { "Imacron", 333, NULL }, { "rcommaaccent", 389, NULL }, { "Zdotaccent", 556, NULL }, { "acircumflex", 500, NULL }, { "cacute", 444, NULL }, { "Ecaron", 611, NULL }, { "icircumflex", 278, NULL }, { "braceright", 400, NULL }, { "quotedblright", 556, NULL }, { "amacron", 500, NULL }, { "sacute", 389, NULL }, { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 675, NULL }, { "zdotaccent", 389, NULL }, { "Atilde", 611, NULL }, { "breve", 333, NULL }, { "bar", 275, NULL }, { "fraction", 167, NULL }, { "less", 675, NULL }, { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, { "Rcaron", 611, NULL }, { "Kcommaaccent", 667, NULL }, { "greater", 675, NULL }, { "atilde", 500, NULL }, { "brokenbar", 275, NULL }, { "quoteleft", 333, NULL }, { "Edotaccent", 611, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth timesRomanWidthsTab[] = { { "Ntilde", 722, NULL }, { "rcaron", 333, NULL }, { "kcommaaccent", 500, NULL }, { "Ncommaaccent", 722, NULL }, { "Zacute", 611, NULL }, { "comma", 250, NULL }, { "cedilla", 333, NULL }, { "plusminus", 564, NULL }, { "circumflex", 333, NULL }, { "dotaccent", 333, NULL }, { "edotaccent", 444, NULL }, { "asciitilde", 541, NULL }, { "colon", 278, NULL }, { "onehalf", 750, NULL }, { "dollar", 500, NULL }, { "Lcaron", 611, NULL }, { "ntilde", 500, NULL }, { "Aogonek", 722, NULL }, { "ncommaaccent", 500, NULL }, { "minus", 564, NULL }, { "Iogonek", 333, NULL }, { "zacute", 444, NULL }, { "yen", 500, NULL }, { "space", 250, NULL }, { "Omacron", 722, NULL }, { "questiondown", 444, NULL }, { "emdash", 1000, NULL }, { "Agrave", 722, NULL }, { "three", 500, NULL }, { "numbersign", 500, NULL }, { "lcaron", 344, NULL }, { "A", 722, NULL }, { "B", 667, NULL }, { "C", 667, NULL }, { "aogonek", 444, NULL }, { "D", 722, NULL }, { "E", 611, NULL }, { "onequarter", 750, NULL }, { "F", 556, NULL }, { "G", 722, NULL }, { "H", 722, NULL }, { "I", 333, NULL }, { "J", 389, NULL }, { "K", 722, NULL }, { "iogonek", 278, NULL }, { "backslash", 278, NULL }, { "L", 611, NULL }, { "periodcentered", 250, NULL }, { "M", 889, NULL }, { "N", 722, NULL }, { "omacron", 500, NULL }, { "Tcommaaccent", 611, NULL }, { "O", 722, NULL }, { "P", 556, NULL }, { "Q", 722, NULL }, { "Uhungarumlaut", 722, NULL }, { "R", 667, NULL }, { "Aacute", 722, NULL }, { "caron", 333, NULL }, { "S", 556, NULL }, { "T", 611, NULL }, { "U", 722, NULL }, { "agrave", 444, NULL }, { "V", 722, NULL }, { "W", 944, NULL }, { "X", 722, NULL }, { "question", 444, NULL }, { "equal", 564, NULL }, { "Y", 722, NULL }, { "Z", 611, NULL }, { "four", 500, NULL }, { "a", 444, NULL }, { "Gcommaaccent", 722, NULL }, { "b", 500, NULL }, { "c", 444, NULL }, { "d", 500, NULL }, { "e", 444, NULL }, { "f", 333, NULL }, { "g", 500, NULL }, { "bullet", 350, NULL }, { "h", 500, NULL }, { "i", 278, NULL }, { "Oslash", 722, NULL }, { "dagger", 500, NULL }, { "j", 278, NULL }, { "k", 500, NULL }, { "l", 278, NULL }, { "m", 778, NULL }, { "n", 500, NULL }, { "tcommaaccent", 278, NULL }, { "o", 500, NULL }, { "ordfeminine", 276, NULL }, { "ring", 333, NULL }, { "p", 500, NULL }, { "q", 500, NULL }, { "uhungarumlaut", 500, NULL }, { "r", 333, NULL }, { "twosuperior", 300, NULL }, { "aacute", 444, NULL }, { "s", 389, NULL }, { "OE", 889, NULL }, { "t", 278, NULL }, { "divide", 564, NULL }, { "u", 500, NULL }, { "Ccaron", 667, NULL }, { "v", 500, NULL }, { "w", 722, NULL }, { "x", 500, NULL }, { "y", 500, NULL }, { "z", 444, NULL }, { "Gbreve", 722, NULL }, { "commaaccent", 250, NULL }, { "hungarumlaut", 333, NULL }, { "Idotaccent", 333, NULL }, { "Nacute", 722, NULL }, { "quotedbl", 408, NULL }, { "gcommaaccent", 500, NULL }, { "mu", 500, NULL }, { "greaterequal", 549, NULL }, { "Scaron", 556, NULL }, { "Lslash", 611, NULL }, { "semicolon", 278, NULL }, { "oslash", 500, NULL }, { "lessequal", 549, NULL }, { "lozenge", 471, NULL }, { "parenright", 333, NULL }, { "ccaron", 444, NULL }, { "Ecircumflex", 611, NULL }, { "gbreve", 500, NULL }, { "trademark", 980, NULL }, { "daggerdbl", 500, NULL }, { "nacute", 500, NULL }, { "macron", 333, NULL }, { "Otilde", 722, NULL }, { "Emacron", 611, NULL }, { "ellipsis", 1000, NULL }, { "scaron", 389, NULL }, { "AE", 889, NULL }, { "Ucircumflex", 722, NULL }, { "lslash", 278, NULL }, { "quotedblleft", 444, NULL }, { "guilsinglright", 333, NULL }, { "hyphen", 333, NULL }, { "quotesingle", 180, NULL }, { "eight", 500, NULL }, { "exclamdown", 333, NULL }, { "endash", 500, NULL }, { "oe", 722, NULL }, { "Abreve", 722, NULL }, { "Umacron", 722, NULL }, { "ecircumflex", 444, NULL }, { "Adieresis", 722, NULL }, { "copyright", 760, NULL }, { "Egrave", 611, NULL }, { "slash", 278, NULL }, { "Edieresis", 611, NULL }, { "otilde", 500, NULL }, { "Idieresis", 333, NULL }, { "parenleft", 333, NULL }, { "one", 500, NULL }, { "emacron", 444, NULL }, { "Odieresis", 722, NULL }, { "ucircumflex", 500, NULL }, { "bracketleft", 333, NULL }, { "Ugrave", 722, NULL }, { "quoteright", 333, NULL }, { "Udieresis", 722, NULL }, { "perthousand", 1000, NULL }, { "Ydieresis", 722, NULL }, { "umacron", 500, NULL }, { "abreve", 444, NULL }, { "Eacute", 611, NULL }, { "adieresis", 444, NULL }, { "egrave", 444, NULL }, { "edieresis", 444, NULL }, { "idieresis", 278, NULL }, { "Eth", 722, NULL }, { "ae", 667, NULL }, { "asterisk", 500, NULL }, { "odieresis", 500, NULL }, { "Uacute", 722, NULL }, { "ugrave", 500, NULL }, { "nine", 500, NULL }, { "five", 500, NULL }, { "udieresis", 500, NULL }, { "Zcaron", 611, NULL }, { "Scommaaccent", 556, NULL }, { "threequarters", 750, NULL }, { "guillemotright", 500, NULL }, { "Ccedilla", 667, NULL }, { "ydieresis", 500, NULL }, { "tilde", 333, NULL }, { "at", 921, NULL }, { "eacute", 444, NULL }, { "underscore", 500, NULL }, { "Euro", 500, NULL }, { "Dcroat", 722, NULL }, { "multiply", 564, NULL }, { "zero", 500, NULL }, { "eth", 500, NULL }, { "Scedilla", 556, NULL }, { "Ograve", 722, NULL }, { "Racute", 667, NULL }, { "partialdiff", 476, NULL }, { "uacute", 500, NULL }, { "braceleft", 480, NULL }, { "Thorn", 556, NULL }, { "zcaron", 444, NULL }, { "scommaaccent", 389, NULL }, { "ccedilla", 444, NULL }, { "Dcaron", 722, NULL }, { "dcroat", 500, NULL }, { "Ocircumflex", 722, NULL }, { "Oacute", 722, NULL }, { "scedilla", 389, NULL }, { "ogonek", 333, NULL }, { "ograve", 500, NULL }, { "racute", 333, NULL }, { "Tcaron", 611, NULL }, { "Eogonek", 611, NULL }, { "thorn", 500, NULL }, { "degree", 400, NULL }, { "registered", 760, NULL }, { "radical", 453, NULL }, { "Aring", 722, NULL }, { "percent", 833, NULL }, { "six", 500, NULL }, { "paragraph", 453, NULL }, { "dcaron", 588, NULL }, { "Uogonek", 722, NULL }, { "two", 500, NULL }, { "summation", 600, NULL }, { "Igrave", 333, NULL }, { "Lacute", 611, NULL }, { "ocircumflex", 500, NULL }, { "oacute", 500, NULL }, { "Uring", 722, NULL }, { "Lcommaaccent", 611, NULL }, { "tcaron", 326, NULL }, { "eogonek", 444, NULL }, { "Delta", 612, NULL }, { "Ohungarumlaut", 722, NULL }, { "asciicircum", 469, NULL }, { "aring", 444, NULL }, { "grave", 333, NULL }, { "uogonek", 500, NULL }, { "bracketright", 333, NULL }, { "Iacute", 333, NULL }, { "ampersand", 778, NULL }, { "igrave", 278, NULL }, { "lacute", 278, NULL }, { "Ncaron", 722, NULL }, { "plus", 564, NULL }, { "uring", 500, NULL }, { "quotesinglbase", 333, NULL }, { "lcommaaccent", 278, NULL }, { "Yacute", 722, NULL }, { "ohungarumlaut", 500, NULL }, { "threesuperior", 300, NULL }, { "acute", 333, NULL }, { "section", 500, NULL }, { "dieresis", 333, NULL }, { "iacute", 278, NULL }, { "quotedblbase", 444, NULL }, { "ncaron", 500, NULL }, { "florin", 500, NULL }, { "yacute", 500, NULL }, { "Rcommaaccent", 667, NULL }, { "fi", 556, NULL }, { "fl", 556, NULL }, { "Acircumflex", 722, NULL }, { "Cacute", 667, NULL }, { "Icircumflex", 333, NULL }, { "guillemotleft", 500, NULL }, { "germandbls", 500, NULL }, { "Amacron", 722, NULL }, { "seven", 500, NULL }, { "Sacute", 556, NULL }, { "ordmasculine", 310, NULL }, { "dotlessi", 278, NULL }, { "sterling", 500, NULL }, { "notequal", 549, NULL }, { "Imacron", 333, NULL }, { "rcommaaccent", 333, NULL }, { "Zdotaccent", 611, NULL }, { "acircumflex", 444, NULL }, { "cacute", 444, NULL }, { "Ecaron", 611, NULL }, { "icircumflex", 278, NULL }, { "braceright", 480, NULL }, { "quotedblright", 444, NULL }, { "amacron", 444, NULL }, { "sacute", 389, NULL }, { "imacron", 278, NULL }, { "cent", 500, NULL }, { "currency", 500, NULL }, { "logicalnot", 564, NULL }, { "zdotaccent", 444, NULL }, { "Atilde", 722, NULL }, { "breve", 333, NULL }, { "bar", 200, NULL }, { "fraction", 167, NULL }, { "less", 564, NULL }, { "ecaron", 444, NULL }, { "guilsinglleft", 333, NULL }, { "exclam", 333, NULL }, { "period", 250, NULL }, { "Rcaron", 667, NULL }, { "Kcommaaccent", 722, NULL }, { "greater", 564, NULL }, { "atilde", 444, NULL }, { "brokenbar", 200, NULL }, { "quoteleft", 333, NULL }, { "Edotaccent", 611, NULL }, { "onesuperior", 300, NULL } }; static BuiltinFontWidth zapfDingbatsWidthsTab[] = { { "a81", 438, NULL }, { "a82", 138, NULL }, { "a83", 277, NULL }, { "a84", 415, NULL }, { "a85", 509, NULL }, { "a86", 410, NULL }, { "a87", 234, NULL }, { "a88", 234, NULL }, { "a89", 390, NULL }, { "a140", 788, NULL }, { "a141", 788, NULL }, { "a142", 788, NULL }, { "a143", 788, NULL }, { "a144", 788, NULL }, { "a145", 788, NULL }, { "a146", 788, NULL }, { "a147", 788, NULL }, { "a148", 788, NULL }, { "a149", 788, NULL }, { "a90", 390, NULL }, { "a91", 276, NULL }, { "a92", 276, NULL }, { "space", 278, NULL }, { "a93", 317, NULL }, { "a94", 317, NULL }, { "a95", 334, NULL }, { "a96", 334, NULL }, { "a97", 392, NULL }, { "a98", 392, NULL }, { "a99", 668, NULL }, { "a150", 788, NULL }, { "a151", 788, NULL }, { "a152", 788, NULL }, { "a153", 788, NULL }, { "a154", 788, NULL }, { "a155", 788, NULL }, { "a156", 788, NULL }, { "a157", 788, NULL }, { "a158", 788, NULL }, { "a159", 788, NULL }, { "a160", 894, NULL }, { "a161", 838, NULL }, { "a162", 924, NULL }, { "a163", 1016, NULL }, { "a164", 458, NULL }, { "a165", 924, NULL }, { "a166", 918, NULL }, { "a167", 927, NULL }, { "a168", 928, NULL }, { "a169", 928, NULL }, { "a170", 834, NULL }, { "a171", 873, NULL }, { "a172", 828, NULL }, { "a173", 924, NULL }, { "a174", 917, NULL }, { "a175", 930, NULL }, { "a176", 931, NULL }, { "a177", 463, NULL }, { "a178", 883, NULL }, { "a179", 836, NULL }, { "a180", 867, NULL }, { "a181", 696, NULL }, { "a182", 874, NULL }, { "a183", 760, NULL }, { "a184", 946, NULL }, { "a185", 865, NULL }, { "a186", 967, NULL }, { "a187", 831, NULL }, { "a188", 873, NULL }, { "a189", 927, NULL }, { "a1", 974, NULL }, { "a2", 961, NULL }, { "a3", 980, NULL }, { "a4", 719, NULL }, { "a5", 789, NULL }, { "a6", 494, NULL }, { "a7", 552, NULL }, { "a8", 537, NULL }, { "a9", 577, NULL }, { "a190", 970, NULL }, { "a191", 918, NULL }, { "a192", 748, NULL }, { "a193", 836, NULL }, { "a194", 771, NULL }, { "a195", 888, NULL }, { "a196", 748, NULL }, { "a197", 771, NULL }, { "a198", 888, NULL }, { "a199", 867, NULL }, { "a10", 692, NULL }, { "a11", 960, NULL }, { "a12", 939, NULL }, { "a13", 549, NULL }, { "a14", 855, NULL }, { "a15", 911, NULL }, { "a16", 933, NULL }, { "a17", 945, NULL }, { "a18", 974, NULL }, { "a19", 755, NULL }, { "a20", 846, NULL }, { "a21", 762, NULL }, { "a22", 761, NULL }, { "a23", 571, NULL }, { "a24", 677, NULL }, { "a25", 763, NULL }, { "a26", 760, NULL }, { "a27", 759, NULL }, { "a28", 754, NULL }, { "a29", 786, NULL }, { "a30", 788, NULL }, { "a31", 788, NULL }, { "a32", 790, NULL }, { "a33", 793, NULL }, { "a34", 794, NULL }, { "a35", 816, NULL }, { "a36", 823, NULL }, { "a37", 789, NULL }, { "a38", 841, NULL }, { "a39", 823, NULL }, { "a40", 833, NULL }, { "a41", 816, NULL }, { "a42", 831, NULL }, { "a43", 923, NULL }, { "a44", 744, NULL }, { "a45", 723, NULL }, { "a46", 749, NULL }, { "a47", 790, NULL }, { "a48", 792, NULL }, { "a49", 695, NULL }, { "a100", 668, NULL }, { "a101", 732, NULL }, { "a102", 544, NULL }, { "a103", 544, NULL }, { "a104", 910, NULL }, { "a105", 911, NULL }, { "a106", 667, NULL }, { "a107", 760, NULL }, { "a108", 760, NULL }, { "a109", 626, NULL }, { "a50", 776, NULL }, { "a51", 768, NULL }, { "a52", 792, NULL }, { "a53", 759, NULL }, { "a54", 707, NULL }, { "a55", 708, NULL }, { "a56", 682, NULL }, { "a57", 701, NULL }, { "a58", 826, NULL }, { "a59", 815, NULL }, { "a110", 694, NULL }, { "a111", 595, NULL }, { "a112", 776, NULL }, { "a117", 690, NULL }, { "a118", 791, NULL }, { "a119", 790, NULL }, { "a60", 789, NULL }, { "a61", 789, NULL }, { "a62", 707, NULL }, { "a63", 687, NULL }, { "a64", 696, NULL }, { "a65", 689, NULL }, { "a66", 786, NULL }, { "a67", 787, NULL }, { "a68", 713, NULL }, { "a69", 791, NULL }, { "a200", 696, NULL }, { "a201", 874, NULL }, { "a120", 788, NULL }, { "a121", 788, NULL }, { "a202", 974, NULL }, { "a122", 788, NULL }, { "a203", 762, NULL }, { "a123", 788, NULL }, { "a204", 759, NULL }, { "a124", 788, NULL }, { "a205", 509, NULL }, { "a125", 788, NULL }, { "a206", 410, NULL }, { "a126", 788, NULL }, { "a127", 788, NULL }, { "a128", 788, NULL }, { "a129", 788, NULL }, { "a70", 785, NULL }, { "a71", 791, NULL }, { "a72", 873, NULL }, { "a73", 761, NULL }, { "a74", 762, NULL }, { "a75", 759, NULL }, { "a76", 892, NULL }, { "a77", 892, NULL }, { "a78", 788, NULL }, { "a79", 784, NULL }, { "a130", 788, NULL }, { "a131", 788, NULL }, { "a132", 788, NULL }, { "a133", 788, NULL }, { "a134", 788, NULL }, { "a135", 788, NULL }, { "a136", 788, NULL }, { "a137", 788, NULL }, { "a138", 788, NULL }, { "a139", 788, NULL } }; BuiltinFont builtinFonts[] = { { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL }, { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL }, { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL }, { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL }, { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL }, { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL }, { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL }, { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL }, { "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL }, { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL }, { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL }, { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL }, { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL }, { "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL } }; BuiltinFont *builtinFontSubst[] = { &builtinFonts[0], &builtinFonts[3], &builtinFonts[1], &builtinFonts[2], &builtinFonts[4], &builtinFonts[7], &builtinFonts[5], &builtinFonts[6], &builtinFonts[12], &builtinFonts[11], &builtinFonts[9], &builtinFonts[10] }; void initBuiltinFontTables() { builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315); builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315); builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315); builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315); builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315); builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316); builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315); builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315); builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190); builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315); builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315); builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315); builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315); builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202); } void freeBuiltinFontTables() { int i; for (i = 0; i < 14; ++i) { delete builtinFonts[i].widths; } } xpdf-3.03/xpdf/OutputDev.h0000644000076400007640000002211511622305345014765 0ustar dereknderekn//======================================================================== // // OutputDev.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef OUTPUTDEV_H #define OUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" class GString; class Gfx; class GfxState; struct GfxColor; class GfxColorSpace; class GfxImageColorMap; class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; class Stream; class Links; class Link; class Catalog; class Page; class Function; //------------------------------------------------------------------------ // OutputDev //------------------------------------------------------------------------ class OutputDev { public: // Constructor. OutputDev() {} // Destructor. virtual ~OutputDev() {} //----- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() = 0; // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() = 0; // Does this device use tilingPatternFill()? If this returns false, // tiling pattern fills will be reduced to a series of other drawing // operations. virtual GBool useTilingPatternFill() { return gFalse; } // Does this device use functionShadedFill(), axialShadedFill(), and // radialShadedFill()? If this returns false, these shaded fills // will be reduced to a series of other drawing operations. virtual GBool useShadedFills() { return gFalse; } // Does this device use drawForm()? If this returns false, // form-type XObjects will be interpreted (i.e., unrolled). virtual GBool useDrawForm() { return gFalse; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() = 0; // Does this device need non-text content? virtual GBool needNonText() { return gTrue; } // Does this device require incCharCount to be called for text on // non-shown layers? virtual GBool needCharCount() { return gFalse; } //----- initialization and control // Set default transform matrix. virtual void setDefaultCTM(double *ctm); // Check to see if a page slice should be displayed. If this // returns false, the page display is aborted. Typically, an // OutputDev will use some alternate means to display the page // before returning false. virtual GBool checkPageSlice(Page *page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL) { return gTrue; } // Start a page. virtual void startPage(int pageNum, GfxState *state) {} // End a page. virtual void endPage() {} // Dump page contents to display. virtual void dump() {} //----- coordinate conversion // Convert between device and user coordinates. virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy); virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy); double *getDefCTM() { return defCTM; } double *getDefICTM() { return defICTM; } //----- save/restore graphics state virtual void saveState(GfxState *state) {} virtual void restoreState(GfxState *state) {} //----- update graphics state virtual void updateAll(GfxState *state); virtual void updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) {} virtual void updateLineDash(GfxState *state) {} virtual void updateFlatness(GfxState *state) {} virtual void updateLineJoin(GfxState *state) {} virtual void updateLineCap(GfxState *state) {} virtual void updateMiterLimit(GfxState *state) {} virtual void updateLineWidth(GfxState *state) {} virtual void updateStrokeAdjust(GfxState *state) {} virtual void updateFillColorSpace(GfxState *state) {} virtual void updateStrokeColorSpace(GfxState *state) {} virtual void updateFillColor(GfxState *state) {} virtual void updateStrokeColor(GfxState *state) {} virtual void updateBlendMode(GfxState *state) {} virtual void updateFillOpacity(GfxState *state) {} virtual void updateStrokeOpacity(GfxState *state) {} virtual void updateFillOverprint(GfxState *state) {} virtual void updateStrokeOverprint(GfxState *state) {} virtual void updateOverprintMode(GfxState *state) {} virtual void updateTransfer(GfxState *state) {} //----- update text state virtual void updateFont(GfxState *state) {} virtual void updateTextMat(GfxState *state) {} virtual void updateCharSpace(GfxState *state) {} virtual void updateRender(GfxState *state) {} virtual void updateRise(GfxState *state) {} virtual void updateWordSpace(GfxState *state) {} virtual void updateHorizScaling(GfxState *state) {} virtual void updateTextPos(GfxState *state) {} virtual void updateTextShift(GfxState *state, double shift) {} virtual void saveTextPos(GfxState *state) {} virtual void restoreTextPos(GfxState *state) {} //----- path painting virtual void stroke(GfxState *state) {} virtual void fill(GfxState *state) {} virtual void eoFill(GfxState *state) {} virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) {} virtual GBool functionShadedFill(GfxState *state, GfxFunctionShading *shading) { return gFalse; } virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading) { return gFalse; } virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading) { return gFalse; } //----- path clipping virtual void clip(GfxState *state) {} virtual void eoClip(GfxState *state) {} virtual void clipToStrokePath(GfxState *state) {} //----- text drawing virtual void beginStringOp(GfxState *state) {} virtual void endStringOp(GfxState *state) {} virtual void beginString(GfxState *state, GString *s) {} virtual void endString(GfxState *state) {} virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode code, int nBytes, Unicode *u, int uLen) {} virtual void drawString(GfxState *state, GString *s) {} virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state) {} virtual void endTextObject(GfxState *state) {} virtual void incCharCount(int nChars) {} virtual void beginActualText(GfxState *state, Unicode *u, int uLen) {} virtual void endActualText(GfxState *state) {} //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap); #if OPI_SUPPORT //----- OPI functions virtual void opiBegin(GfxState *state, Dict *opiDict); virtual void opiEnd(GfxState *state, Dict *opiDict); #endif //----- Type 3 font operators virtual void type3D0(GfxState *state, double wx, double wy) {} virtual void type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) {} //----- form XObjects virtual void drawForm(Ref id) {} //----- PostScript XObjects virtual void psXObject(Stream *psStream, Stream *level1Stream) {} //----- transparency groups and soft masks virtual void beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask) {} virtual void endTransparencyGroup(GfxState *state) {} virtual void paintTransparencyGroup(GfxState *state, double *bbox) {} virtual void setSoftMask(GfxState *state, double *bbox, GBool alpha, Function *transferFunc, GfxColor *backdropColor) {} virtual void clearSoftMask(GfxState *state) {} //----- links virtual void processLink(Link *link) {} #if 1 //~tmp: turn off anti-aliasing temporarily virtual void setInShading(GBool sh) {} #endif private: double defCTM[6]; // default coordinate transform matrix double defICTM[6]; // inverse of default CTM }; #endif xpdf-3.03/xpdf/XPDFTree.h0000644000076400007640000000212111622305345014402 0ustar dereknderekn//======================================================================== // // XPDFTree.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XPDFTREE_H #define XPDFTREE_H #include #include extern "C" { externalref WidgetClass xpdfTreeWidgetClass; typedef struct _XPDFTreeClassRec *XPDFTreeWidgetClass; typedef struct _XPDFTreeRec *XPDFTreeWidget; #ifndef XPDFIsTree #define XPDFIsTree(w) XtIsSubclass(w, xpdfTreeWidgetClass) #endif #define XPDFNentryParent "entryParent" #define XPDFNentryExpanded "entryExpanded" #define XPDFNentryPosition "entryPosition" #define XPDFNselectionCallback "selectionCallback" #define XPDFCentryParent "EntryParent" #define XPDFCentryExpanded "EntryExpanded" #define XPDFCentryPosition "EntryPosition" typedef struct { int reason; XEvent *event; Widget selectedItem; } XPDFTreeSelectCallbackStruct; extern Widget XPDFCreateTree(Widget parent, char *name, ArgList argList, Cardinal argCount); } // extern "C" #endif xpdf-3.03/xpdf/pdfinfo.cc0000644000076400007640000002545011622305345014616 0ustar dereknderekn//======================================================================== // // pdfinfo.cc // // Copyright 1998-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include #include #include #include #include #include "parseargs.h" #include "GString.h" #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "Stream.h" #include "Array.h" #include "Dict.h" #include "XRef.h" #include "Catalog.h" #include "Page.h" #include "PDFDoc.h" #include "CharTypes.h" #include "UnicodeMap.h" #include "PDFDocEncoding.h" #include "Error.h" #include "config.h" static void printInfoString(Dict *infoDict, const char *key, const char *text, UnicodeMap *uMap); static void printInfoDate(Dict *infoDict, const char *key, const char *text); static void printBox(const char *text, PDFRectangle *box); static int firstPage = 1; static int lastPage = 0; static GBool printBoxes = gFalse; static GBool printMetadata = gFalse; static GBool rawDates = gFalse; static char textEncName[128] = ""; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to convert"}, {"-l", argInt, &lastPage, 0, "last page to convert"}, {"-box", argFlag, &printBoxes, 0, "print the page bounding boxes"}, {"-meta", argFlag, &printMetadata, 0, "print the document metadata (XML)"}, {"-rawdates", argFlag, &rawDates, 0, "print the undecoded date strings directly from the PDF file"}, {"-enc", argString, textEncName, sizeof(textEncName), "output text encoding name"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; GString *ownerPW, *userPW; UnicodeMap *uMap; Page *page; Object info, xfa; Object *acroForm; char buf[256]; double w, h, wISO, hISO; FILE *f; GString *metadata; GBool ok; int exitCode; int pg, i; GBool multiPage; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || argc != 2 || printVersion || printHelp) { fprintf(stderr, "pdfinfo version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdfinfo", "", argDesc); } goto err0; } fileName = new GString(argv[1]); // read config file globalParams = new GlobalParams(cfgFileName); if (textEncName[0]) { globalParams->setTextEncoding(textEncName); } // get mapping to output encoding if (!(uMap = globalParams->getTextEncoding())) { error(errConfig, -1, "Couldn't get text encoding"); delete fileName; goto err1; } // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err2; } // get page range if (firstPage < 1) { firstPage = 1; } if (lastPage == 0) { multiPage = gFalse; lastPage = 1; } else { multiPage = gTrue; } if (lastPage < 1 || lastPage > doc->getNumPages()) { lastPage = doc->getNumPages(); } // print doc info doc->getDocInfo(&info); if (info.isDict()) { printInfoString(info.getDict(), "Title", "Title: ", uMap); printInfoString(info.getDict(), "Subject", "Subject: ", uMap); printInfoString(info.getDict(), "Keywords", "Keywords: ", uMap); printInfoString(info.getDict(), "Author", "Author: ", uMap); printInfoString(info.getDict(), "Creator", "Creator: ", uMap); printInfoString(info.getDict(), "Producer", "Producer: ", uMap); if (rawDates) { printInfoString(info.getDict(), "CreationDate", "CreationDate: ", uMap); printInfoString(info.getDict(), "ModDate", "ModDate: ", uMap); } else { printInfoDate(info.getDict(), "CreationDate", "CreationDate: "); printInfoDate(info.getDict(), "ModDate", "ModDate: "); } } info.free(); // print tagging info printf("Tagged: %s\n", doc->getStructTreeRoot()->isDict() ? "yes" : "no"); // print form info if ((acroForm = doc->getCatalog()->getAcroForm())->isDict()) { acroForm->dictLookup("XFA", &xfa); if (xfa.isStream() || xfa.isArray()) { printf("Form: XFA\n"); } else { printf("Form: AcroForm\n"); } xfa.free(); } else { printf("Form: none\n"); } // print page count printf("Pages: %d\n", doc->getNumPages()); // print encryption info printf("Encrypted: "); if (doc->isEncrypted()) { printf("yes (print:%s copy:%s change:%s addNotes:%s)\n", doc->okToPrint(gTrue) ? "yes" : "no", doc->okToCopy(gTrue) ? "yes" : "no", doc->okToChange(gTrue) ? "yes" : "no", doc->okToAddNotes(gTrue) ? "yes" : "no"); } else { printf("no\n"); } // print page size for (pg = firstPage; pg <= lastPage; ++pg) { w = doc->getPageCropWidth(pg); h = doc->getPageCropHeight(pg); if (multiPage) { printf("Page %4d size: %g x %g pts", pg, w, h); } else { printf("Page size: %g x %g pts", w, h); } if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) || (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) { printf(" (letter)"); } else { hISO = sqrt(sqrt(2.0)) * 7200 / 2.54; wISO = hISO / sqrt(2.0); for (i = 0; i <= 6; ++i) { if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) || (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) { printf(" (A%d)", i); break; } hISO = wISO; wISO /= sqrt(2.0); } } printf("\n"); } // print the boxes if (printBoxes) { if (multiPage) { for (pg = firstPage; pg <= lastPage; ++pg) { page = doc->getCatalog()->getPage(pg); sprintf(buf, "Page %4d MediaBox: ", pg); printBox(buf, page->getMediaBox()); sprintf(buf, "Page %4d CropBox: ", pg); printBox(buf, page->getCropBox()); sprintf(buf, "Page %4d BleedBox: ", pg); printBox(buf, page->getBleedBox()); sprintf(buf, "Page %4d TrimBox: ", pg); printBox(buf, page->getTrimBox()); sprintf(buf, "Page %4d ArtBox: ", pg); printBox(buf, page->getArtBox()); } } else { page = doc->getCatalog()->getPage(firstPage); printBox("MediaBox: ", page->getMediaBox()); printBox("CropBox: ", page->getCropBox()); printBox("BleedBox: ", page->getBleedBox()); printBox("TrimBox: ", page->getTrimBox()); printBox("ArtBox: ", page->getArtBox()); } } // print file size #ifdef VMS f = fopen(fileName->getCString(), "rb", "ctx=stm"); #else f = fopen(fileName->getCString(), "rb"); #endif if (f) { #if HAVE_FSEEKO fseeko(f, 0, SEEK_END); printf("File size: %u bytes\n", (Guint)ftello(f)); #elif HAVE_FSEEK64 fseek64(f, 0, SEEK_END); printf("File size: %u bytes\n", (Guint)ftell64(f)); #else fseek(f, 0, SEEK_END); printf("File size: %d bytes\n", (int)ftell(f)); #endif fclose(f); } // print linearization info printf("Optimized: %s\n", doc->isLinearized() ? "yes" : "no"); // print PDF version printf("PDF version: %.1f\n", doc->getPDFVersion()); // print the metadata if (printMetadata && (metadata = doc->readMetadata())) { fputs("Metadata:\n", stdout); fputs(metadata->getCString(), stdout); fputc('\n', stdout); delete metadata; } exitCode = 0; // clean up err2: uMap->decRefCnt(); delete doc; err1: delete globalParams; err0: // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } static void printInfoString(Dict *infoDict, const char *key, const char *text, UnicodeMap *uMap) { Object obj; GString *s1; GBool isUnicode; Unicode u; char buf[8]; int i, n; if (infoDict->lookup(key, &obj)->isString()) { fputs(text, stdout); s1 = obj.getString(); if ((s1->getChar(0) & 0xff) == 0xfe && (s1->getChar(1) & 0xff) == 0xff) { isUnicode = gTrue; i = 2; } else { isUnicode = gFalse; i = 0; } while (i < obj.getString()->getLength()) { if (isUnicode) { u = ((s1->getChar(i) & 0xff) << 8) | (s1->getChar(i+1) & 0xff); i += 2; } else { u = pdfDocEncoding[s1->getChar(i) & 0xff]; ++i; } n = uMap->mapUnicode(u, buf, sizeof(buf)); fwrite(buf, 1, n, stdout); } fputc('\n', stdout); } obj.free(); } static void printInfoDate(Dict *infoDict, const char *key, const char *text) { Object obj; char *s; int year, mon, day, hour, min, sec, n; struct tm tmStruct; char buf[256]; if (infoDict->lookup(key, &obj)->isString()) { fputs(text, stdout); s = obj.getString()->getCString(); if (s[0] == 'D' && s[1] == ':') { s += 2; } if ((n = sscanf(s, "%4d%2d%2d%2d%2d%2d", &year, &mon, &day, &hour, &min, &sec)) >= 1) { switch (n) { case 1: mon = 1; case 2: day = 1; case 3: hour = 0; case 4: min = 0; case 5: sec = 0; } tmStruct.tm_year = year - 1900; tmStruct.tm_mon = mon - 1; tmStruct.tm_mday = day; tmStruct.tm_hour = hour; tmStruct.tm_min = min; tmStruct.tm_sec = sec; tmStruct.tm_wday = -1; tmStruct.tm_yday = -1; tmStruct.tm_isdst = -1; // compute the tm_wday and tm_yday fields if (mktime(&tmStruct) != (time_t)-1 && strftime(buf, sizeof(buf), "%c", &tmStruct)) { fputs(buf, stdout); } else { fputs(s, stdout); } } else { fputs(s, stdout); } fputc('\n', stdout); } obj.free(); } static void printBox(const char *text, PDFRectangle *box) { printf("%s%8.2f %8.2f %8.2f %8.2f\n", text, box->x1, box->y1, box->x2, box->y2); } xpdf-3.03/xpdf/TextOutputDev.cc0000644000076400007640000032663511622305345016006 0ustar dereknderekn//======================================================================== // // TextOutputDev.cc // // Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #ifdef WIN32 #include // for O_BINARY #include // for setmode #endif #include "gmem.h" #include "GString.h" #include "GList.h" #include "config.h" #include "Error.h" #include "GlobalParams.h" #include "UnicodeMap.h" #include "UnicodeTypeTable.h" #include "GfxState.h" #include "Link.h" #include "TextOutputDev.h" #ifdef MACOS // needed for setting type/creator of MacOS files #include "ICSupport.h" #endif //------------------------------------------------------------------------ // parameters //------------------------------------------------------------------------ // Each bucket in a text pool includes baselines within a range of // this many points. #define textPoolStep 4 // Inter-character space width which will cause addChar to start a new // word. #define minWordBreakSpace 0.1 // Negative inter-character space width, i.e., overlap, which will // cause addChar to start a new word. #define minDupBreakOverlap 0.2 // Max distance between baselines of two lines within a block, as a // fraction of the font size. #define maxLineSpacingDelta 1.5 // Max difference in primary font sizes on two lines in the same // block. Delta1 is used when examining new lines above and below the // current block; delta2 is used when examining text that overlaps the // current block; delta3 is used when examining text to the left and // right of the current block. #define maxBlockFontSizeDelta1 0.05 #define maxBlockFontSizeDelta2 0.6 #define maxBlockFontSizeDelta3 0.2 // Max difference in font sizes inside a word. #define maxWordFontSizeDelta 0.05 // Maximum distance between baselines of two words on the same line, // e.g., distance between subscript or superscript and the primary // baseline, as a fraction of the font size. #define maxIntraLineDelta 0.5 // Minimum inter-word spacing, as a fraction of the font size. (Only // used for raw ordering.) #define minWordSpacing 0.15 // Maximum inter-word spacing, as a fraction of the font size. #define maxWordSpacing 1.5 // Maximum horizontal spacing which will allow a word to be pulled // into a block. #define minColSpacing1 0.3 // Minimum spacing between columns, as a fraction of the font size. #define minColSpacing2 1.0 // Maximum vertical spacing between blocks within a flow, as a // multiple of the font size. #define maxBlockSpacing 2.5 // Minimum spacing between characters within a word, as a fraction of // the font size. #define minCharSpacing -0.2 // Maximum spacing between characters within a word, as a fraction of // the font size, when there is no obvious extra-wide character // spacing. #define maxCharSpacing 0.03 // When extra-wide character spacing is detected, the inter-character // space threshold is set to the minimum inter-character space // multiplied by this constant. #define maxWideCharSpacingMul 1.3 // Upper limit on spacing between characters in a word. #define maxWideCharSpacing 0.4 // Max difference in primary,secondary coordinates (as a fraction of // the font size) allowed for duplicated text (fake boldface, drop // shadows) which is to be discarded. #define dupMaxPriDelta 0.1 #define dupMaxSecDelta 0.2 // Max width of underlines (in points). #define maxUnderlineWidth 3 // Min distance between baseline and underline (in points). //~ this should be font-size-dependent #define minUnderlineGap -2 // Max distance between baseline and underline (in points). //~ this should be font-size-dependent #define maxUnderlineGap 4 // Max horizontal distance between edge of word and start of underline // (in points). //~ this should be font-size-dependent #define underlineSlack 1 // Max distance between edge of text and edge of link border #define hyperlinkSlack 2 //------------------------------------------------------------------------ // TextUnderline //------------------------------------------------------------------------ class TextUnderline { public: TextUnderline(double x0A, double y0A, double x1A, double y1A) { x0 = x0A; y0 = y0A; x1 = x1A; y1 = y1A; horiz = y0 == y1; } ~TextUnderline() {} double x0, y0, x1, y1; GBool horiz; }; //------------------------------------------------------------------------ // TextLink //------------------------------------------------------------------------ class TextLink { public: TextLink(int xMinA, int yMinA, int xMaxA, int yMaxA, Link *linkA) { xMin = xMinA; yMin = yMinA; xMax = xMaxA; yMax = yMaxA; link = linkA; } ~TextLink() {} int xMin, yMin, xMax, yMax; Link *link; }; //------------------------------------------------------------------------ // TextFontInfo //------------------------------------------------------------------------ TextFontInfo::TextFontInfo(GfxState *state) { gfxFont = state->getFont(); #if TEXTOUT_WORD_LIST fontName = (gfxFont && gfxFont->getName()) ? gfxFont->getName()->copy() : (GString *)NULL; flags = gfxFont ? gfxFont->getFlags() : 0; #endif } TextFontInfo::~TextFontInfo() { #if TEXTOUT_WORD_LIST if (fontName) { delete fontName; } #endif } GBool TextFontInfo::matches(GfxState *state) { return state->getFont() == gfxFont; } //------------------------------------------------------------------------ // TextWord //------------------------------------------------------------------------ TextWord::TextWord(GfxState *state, int rotA, double x0, double y0, TextFontInfo *fontA, double fontSizeA) { GfxFont *gfxFont; double x, y, ascent, descent; int wMode; rot = rotA; font = fontA; fontSize = fontSizeA; state->transform(x0, y0, &x, &y); if ((gfxFont = font->gfxFont)) { ascent = gfxFont->getAscent() * fontSize; descent = gfxFont->getDescent() * fontSize; wMode = gfxFont->getWMode(); } else { // this means that the PDF file draws text without a current font, // which should never happen ascent = 0.95 * fontSize; descent = -0.35 * fontSize; wMode = 0; } if (wMode) { // vertical writing mode // NB: the rotation value has been incremented by 1 (in // TextPage::beginWord()) for vertical writing mode switch (rot) { case 0: yMin = y - fontSize; yMax = y; base = y; break; case 1: xMin = x; xMax = x + fontSize; base = x; break; case 2: yMin = y; yMax = y + fontSize; base = y; break; case 3: xMin = x - fontSize; xMax = x; base = x; break; } } else { // horizontal writing mode switch (rot) { case 0: yMin = y - ascent; yMax = y - descent; if (yMin == yMax) { // this is a sanity check for a case that shouldn't happen -- but // if it does happen, we want to avoid dividing by zero later yMin = y; yMax = y + 1; } base = y; break; case 1: xMin = x + descent; xMax = x + ascent; if (xMin == xMax) { // this is a sanity check for a case that shouldn't happen -- but // if it does happen, we want to avoid dividing by zero later xMin = x; xMax = x + 1; } base = x; break; case 2: yMin = y + descent; yMax = y + ascent; if (yMin == yMax) { // this is a sanity check for a case that shouldn't happen -- but // if it does happen, we want to avoid dividing by zero later yMin = y; yMax = y + 1; } base = y; break; case 3: xMin = x - ascent; xMax = x - descent; if (xMin == xMax) { // this is a sanity check for a case that shouldn't happen -- but // if it does happen, we want to avoid dividing by zero later xMin = x; xMax = x + 1; } base = x; break; } } text = NULL; edge = NULL; charPos = NULL; len = size = 0; spaceAfter = gFalse; next = NULL; #if TEXTOUT_WORD_LIST GfxRGB rgb; if ((state->getRender() & 3) == 1) { state->getStrokeRGB(&rgb); } else { state->getFillRGB(&rgb); } colorR = colToDbl(rgb.r); colorG = colToDbl(rgb.g); colorB = colToDbl(rgb.b); #endif underlined = gFalse; link = NULL; } TextWord::~TextWord() { gfree(text); gfree(edge); gfree(charPos); } void TextWord::addChar(GfxState *state, double x, double y, double dx, double dy, int charPosA, int charLen, Unicode u) { int wMode; if (len == size) { size += 16; text = (Unicode *)greallocn(text, size, sizeof(Unicode)); edge = (double *)greallocn(edge, size + 1, sizeof(double)); charPos = (int *)greallocn(charPos, size + 1, sizeof(int)); } text[len] = u; charPos[len] = charPosA; charPos[len + 1] = charPosA + charLen; wMode = font->gfxFont ? font->gfxFont->getWMode() : 0; if (wMode) { // vertical writing mode // NB: the rotation value has been incremented by 1 (in // TextPage::beginWord()) for vertical writing mode switch (rot) { case 0: if (len == 0) { xMin = x - fontSize; } edge[len] = x - fontSize; xMax = edge[len+1] = x; break; case 1: if (len == 0) { yMin = y - fontSize; } edge[len] = y - fontSize; yMax = edge[len+1] = y; break; case 2: if (len == 0) { xMax = x + fontSize; } edge[len] = x + fontSize; xMin = edge[len+1] = x; break; case 3: if (len == 0) { yMax = y + fontSize; } edge[len] = y + fontSize; yMin = edge[len+1] = y; break; } } else { // horizontal writing mode switch (rot) { case 0: if (len == 0) { xMin = x; } edge[len] = x; xMax = edge[len+1] = x + dx; break; case 1: if (len == 0) { yMin = y; } edge[len] = y; yMax = edge[len+1] = y + dy; break; case 2: if (len == 0) { xMax = x; } edge[len] = x; xMin = edge[len+1] = x + dx; break; case 3: if (len == 0) { yMax = y; } edge[len] = y; yMin = edge[len+1] = y + dy; break; } } ++len; } void TextWord::merge(TextWord *word) { int i; if (word->xMin < xMin) { xMin = word->xMin; } if (word->yMin < yMin) { yMin = word->yMin; } if (word->xMax > xMax) { xMax = word->xMax; } if (word->yMax > yMax) { yMax = word->yMax; } if (len + word->len > size) { size = len + word->len; text = (Unicode *)greallocn(text, size, sizeof(Unicode)); edge = (double *)greallocn(edge, size + 1, sizeof(double)); charPos = (int *)greallocn(charPos, size + 1, sizeof(int)); } for (i = 0; i < word->len; ++i) { text[len + i] = word->text[i]; edge[len + i] = word->edge[i]; charPos[len + i] = word->charPos[i]; } edge[len + word->len] = word->edge[word->len]; charPos[len + word->len] = word->charPos[word->len]; len += word->len; } inline int TextWord::primaryCmp(TextWord *word) { double cmp; cmp = 0; // make gcc happy switch (rot) { case 0: cmp = xMin - word->xMin; break; case 1: cmp = yMin - word->yMin; break; case 2: cmp = word->xMax - xMax; break; case 3: cmp = word->yMax - yMax; break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } double TextWord::primaryDelta(TextWord *word) { double delta; delta = 0; // make gcc happy switch (rot) { case 0: delta = word->xMin - xMax; break; case 1: delta = word->yMin - yMax; break; case 2: delta = xMin - word->xMax; break; case 3: delta = yMin - word->yMax; break; } return delta; } int TextWord::cmpYX(const void *p1, const void *p2) { TextWord *word1 = *(TextWord **)p1; TextWord *word2 = *(TextWord **)p2; double cmp; cmp = word1->yMin - word2->yMin; if (cmp == 0) { cmp = word1->xMin - word2->xMin; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } #if TEXTOUT_WORD_LIST GString *TextWord::getText() { GString *s; UnicodeMap *uMap; char buf[8]; int n, i; s = new GString(); if (!(uMap = globalParams->getTextEncoding())) { return s; } for (i = 0; i < len; ++i) { n = uMap->mapUnicode(text[i], buf, sizeof(buf)); s->append(buf, n); } uMap->decRefCnt(); return s; } void TextWord::getCharBBox(int charIdx, double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) { if (charIdx < 0 || charIdx >= len) { return; } switch (rot) { case 0: *xMinA = edge[charIdx]; *xMaxA = edge[charIdx + 1]; *yMinA = yMin; *yMaxA = yMax; break; case 1: *xMinA = xMin; *xMaxA = xMax; *yMinA = edge[charIdx]; *yMaxA = edge[charIdx + 1]; break; case 2: *xMinA = edge[charIdx + 1]; *xMaxA = edge[charIdx]; *yMinA = yMin; *yMaxA = yMax; break; case 3: *xMinA = xMin; *xMaxA = xMax; *yMinA = edge[charIdx + 1]; *yMaxA = edge[charIdx]; break; } } #endif // TEXTOUT_WORD_LIST //------------------------------------------------------------------------ // TextPool //------------------------------------------------------------------------ TextPool::TextPool() { minBaseIdx = 0; maxBaseIdx = -1; pool = NULL; cursor = NULL; cursorBaseIdx = -1; } TextPool::~TextPool() { int baseIdx; TextWord *word, *word2; for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { for (word = pool[baseIdx - minBaseIdx]; word; word = word2) { word2 = word->next; delete word; } } gfree(pool); } int TextPool::getBaseIdx(double base) { int baseIdx; baseIdx = (int)(base / textPoolStep); if (baseIdx < minBaseIdx) { return minBaseIdx; } if (baseIdx > maxBaseIdx) { return maxBaseIdx; } return baseIdx; } void TextPool::addWord(TextWord *word) { TextWord **newPool; int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx; TextWord *w0, *w1; // expand the array if needed wordBaseIdx = (int)(word->base / textPoolStep); if (minBaseIdx > maxBaseIdx) { minBaseIdx = wordBaseIdx - 128; maxBaseIdx = wordBaseIdx + 128; pool = (TextWord **)gmallocn(maxBaseIdx - minBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) { pool[baseIdx - minBaseIdx] = NULL; } } else if (wordBaseIdx < minBaseIdx) { newMinBaseIdx = wordBaseIdx - 128; newPool = (TextWord **)gmallocn(maxBaseIdx - newMinBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) { newPool[baseIdx - newMinBaseIdx] = NULL; } memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool, (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *)); gfree(pool); pool = newPool; minBaseIdx = newMinBaseIdx; } else if (wordBaseIdx > maxBaseIdx) { newMaxBaseIdx = wordBaseIdx + 128; pool = (TextWord **)greallocn(pool, newMaxBaseIdx - minBaseIdx + 1, sizeof(TextWord *)); for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) { pool[baseIdx - minBaseIdx] = NULL; } maxBaseIdx = newMaxBaseIdx; } // insert the new word if (cursor && wordBaseIdx == cursorBaseIdx && word->primaryCmp(cursor) >= 0) { w0 = cursor; w1 = cursor->next; } else { w0 = NULL; w1 = pool[wordBaseIdx - minBaseIdx]; } for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ; word->next = w1; if (w0) { w0->next = word; } else { pool[wordBaseIdx - minBaseIdx] = word; } cursor = word; cursorBaseIdx = wordBaseIdx; } //------------------------------------------------------------------------ // TextLine //------------------------------------------------------------------------ TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) { blk = blkA; rot = rotA; xMin = yMin = 0; xMax = yMax = -1; base = baseA; words = lastWord = NULL; text = NULL; edge = NULL; col = NULL; len = 0; convertedLen = 0; hyphenated = gFalse; next = NULL; } TextLine::~TextLine() { TextWord *word; while (words) { word = words; words = words->next; delete word; } gfree(text); gfree(edge); gfree(col); } void TextLine::addWord(TextWord *word) { if (lastWord) { lastWord->next = word; } else { words = word; } lastWord = word; if (xMin > xMax) { xMin = word->xMin; xMax = word->xMax; yMin = word->yMin; yMax = word->yMax; } else { if (word->xMin < xMin) { xMin = word->xMin; } if (word->xMax > xMax) { xMax = word->xMax; } if (word->yMin < yMin) { yMin = word->yMin; } if (word->yMax > yMax) { yMax = word->yMax; } } } double TextLine::primaryDelta(TextLine *line) { double delta; delta = 0; // make gcc happy switch (rot) { case 0: delta = line->xMin - xMax; break; case 1: delta = line->yMin - yMax; break; case 2: delta = xMin - line->xMax; break; case 3: delta = yMin - line->yMax; break; } return delta; } int TextLine::primaryCmp(TextLine *line) { double cmp; cmp = 0; // make gcc happy switch (rot) { case 0: cmp = xMin - line->xMin; break; case 1: cmp = yMin - line->yMin; break; case 2: cmp = line->xMax - xMax; break; case 3: cmp = line->yMax - yMax; break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextLine::secondaryCmp(TextLine *line) { double cmp; cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base; return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextLine::cmpYX(TextLine *line) { int cmp; if ((cmp = secondaryCmp(line))) { return cmp; } return primaryCmp(line); } int TextLine::cmpXY(const void *p1, const void *p2) { TextLine *line1 = *(TextLine **)p1; TextLine *line2 = *(TextLine **)p2; int cmp; if ((cmp = line1->primaryCmp(line2))) { return cmp; } return line1->secondaryCmp(line2); } void TextLine::coalesce(UnicodeMap *uMap) { TextWord *word0, *word1; double space, delta, minSpace; GBool isUnicode; char buf[8]; int i, j; if (words->next) { // compute the inter-word space threshold if (words->len > 1 || words->next->len > 1) { minSpace = 0; } else { minSpace = words->primaryDelta(words->next); for (word0 = words->next, word1 = word0->next; word1 && minSpace > 0; word0 = word1, word1 = word0->next) { if (word1->len > 1) { minSpace = 0; } delta = word0->primaryDelta(word1); if (delta < minSpace) { minSpace = delta; } } } if (minSpace <= 0) { space = maxCharSpacing * words->fontSize; } else { space = maxWideCharSpacingMul * minSpace; if (space > maxWideCharSpacing * words->fontSize) { space = maxWideCharSpacing * words->fontSize; } } // merge words word0 = words; word1 = words->next; while (word1) { if (word0->primaryDelta(word1) >= space) { word0->spaceAfter = gTrue; word0 = word1; word1 = word1->next; } else if (word0->font == word1->font && word0->underlined == word1->underlined && fabs(word0->fontSize - word1->fontSize) < maxWordFontSizeDelta * words->fontSize && word1->charPos[0] == word0->charPos[word0->len]) { word0->merge(word1); word0->next = word1->next; delete word1; word1 = word0->next; } else { word0 = word1; word1 = word1->next; } } } // build the line text isUnicode = uMap ? uMap->isUnicode() : gFalse; len = 0; for (word1 = words; word1; word1 = word1->next) { len += word1->len; if (word1->spaceAfter) { ++len; } } text = (Unicode *)gmallocn(len, sizeof(Unicode)); edge = (double *)gmallocn(len + 1, sizeof(double)); i = 0; for (word1 = words; word1; word1 = word1->next) { for (j = 0; j < word1->len; ++j) { text[i] = word1->text[j]; edge[i] = word1->edge[j]; ++i; } edge[i] = word1->edge[word1->len]; if (word1->spaceAfter) { text[i] = (Unicode)0x0020; ++i; } } // compute convertedLen and set up the col array col = (int *)gmallocn(len + 1, sizeof(int)); convertedLen = 0; for (i = 0; i < len; ++i) { col[i] = convertedLen; if (isUnicode) { ++convertedLen; } else if (uMap) { convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf)); } } col[len] = convertedLen; // check for hyphen at end of line //~ need to check for other chars used as hyphens hyphenated = text[len - 1] == (Unicode)'-'; } //------------------------------------------------------------------------ // TextLineFrag //------------------------------------------------------------------------ class TextLineFrag { public: TextLine *line; // the line object int start, len; // offset and length of this fragment // (in Unicode chars) double xMin, xMax; // bounding box coordinates double yMin, yMax; double base; // baseline virtual coordinate int col; // first column void init(TextLine *lineA, int startA, int lenA); void computeCoords(GBool oneRot); static int cmpYXPrimaryRot(const void *p1, const void *p2); static int cmpYXLineRot(const void *p1, const void *p2); static int cmpXYLineRot(const void *p1, const void *p2); static int cmpXYColumnPrimaryRot(const void *p1, const void *p2); static int cmpXYColumnLineRot(const void *p1, const void *p2); }; void TextLineFrag::init(TextLine *lineA, int startA, int lenA) { line = lineA; start = startA; len = lenA; col = line->col[start]; } void TextLineFrag::computeCoords(GBool oneRot) { TextBlock *blk; double d0, d1, d2, d3, d4; if (oneRot) { switch (line->rot) { case 0: xMin = line->edge[start]; xMax = line->edge[start + len]; yMin = line->yMin; yMax = line->yMax; break; case 1: xMin = line->xMin; xMax = line->xMax; yMin = line->edge[start]; yMax = line->edge[start + len]; break; case 2: xMin = line->edge[start + len]; xMax = line->edge[start]; yMin = line->yMin; yMax = line->yMax; break; case 3: xMin = line->xMin; xMax = line->xMax; yMin = line->edge[start + len]; yMax = line->edge[start]; break; } base = line->base; } else { if (line->rot == 0 && line->blk->page->primaryRot == 0) { xMin = line->edge[start]; xMax = line->edge[start + len]; yMin = line->yMin; yMax = line->yMax; base = line->base; } else { blk = line->blk; d0 = line->edge[start]; d1 = line->edge[start + len]; d2 = d3 = d4 = 0; // make gcc happy switch (line->rot) { case 0: d2 = line->yMin; d3 = line->yMax; d4 = line->base; d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin); d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin); d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin); d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin); d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin); break; case 1: d2 = line->xMax; d3 = line->xMin; d4 = line->base; d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin); d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin); d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin); d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin); d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin); break; case 2: d2 = line->yMax; d3 = line->yMin; d4 = line->base; d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin); d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin); d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin); d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin); d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin); break; case 3: d2 = line->xMin; d3 = line->xMax; d4 = line->base; d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin); d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin); d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin); d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin); d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin); break; } switch (line->blk->page->primaryRot) { case 0: xMin = blk->xMin + d0 * (blk->xMax - blk->xMin); xMax = blk->xMin + d1 * (blk->xMax - blk->xMin); yMin = blk->yMin + d2 * (blk->yMax - blk->yMin); yMax = blk->yMin + d3 * (blk->yMax - blk->yMin); base = blk->yMin + d4 * (blk->yMax - blk->yMin); break; case 1: xMin = blk->xMax - d3 * (blk->xMax - blk->xMin); xMax = blk->xMax - d2 * (blk->xMax - blk->xMin); yMin = blk->yMin + d0 * (blk->yMax - blk->yMin); yMax = blk->yMin + d1 * (blk->yMax - blk->yMin); base = blk->xMax - d4 * (blk->xMax - blk->xMin); break; case 2: xMin = blk->xMax - d1 * (blk->xMax - blk->xMin); xMax = blk->xMax - d0 * (blk->xMax - blk->xMin); yMin = blk->yMax - d3 * (blk->yMax - blk->yMin); yMax = blk->yMax - d2 * (blk->yMax - blk->yMin); base = blk->yMax - d4 * (blk->yMax - blk->yMin); break; case 3: xMin = blk->xMin + d2 * (blk->xMax - blk->xMin); xMax = blk->xMin + d3 * (blk->xMax - blk->xMin); yMin = blk->yMax - d1 * (blk->yMax - blk->yMin); yMax = blk->yMax - d0 * (blk->yMax - blk->yMin); base = blk->xMin + d4 * (blk->xMax - blk->xMin); break; } } } } int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) { TextLineFrag *frag1 = (TextLineFrag *)p1; TextLineFrag *frag2 = (TextLineFrag *)p2; double cmp; cmp = 0; // make gcc happy switch (frag1->line->blk->page->primaryRot) { case 0: if (fabs(cmp = frag1->yMin - frag2->yMin) < 0.01) { cmp = frag1->xMin - frag2->xMin; } break; case 1: if (fabs(cmp = frag2->xMax - frag1->xMax) < 0.01) { cmp = frag1->yMin - frag2->yMin; } break; case 2: if (fabs(cmp = frag2->yMin - frag1->yMin) < 0.01) { cmp = frag2->xMax - frag1->xMax; } break; case 3: if (fabs(cmp = frag1->xMax - frag2->xMax) < 0.01) { cmp = frag2->yMax - frag1->yMax; } break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) { TextLineFrag *frag1 = (TextLineFrag *)p1; TextLineFrag *frag2 = (TextLineFrag *)p2; double cmp; cmp = 0; // make gcc happy switch (frag1->line->rot) { case 0: if ((cmp = frag1->yMin - frag2->yMin) == 0) { cmp = frag1->xMin - frag2->xMin; } break; case 1: if ((cmp = frag2->xMax - frag1->xMax) == 0) { cmp = frag1->yMin - frag2->yMin; } break; case 2: if ((cmp = frag2->yMin - frag1->yMin) == 0) { cmp = frag2->xMax - frag1->xMax; } break; case 3: if ((cmp = frag1->xMax - frag2->xMax) == 0) { cmp = frag2->yMax - frag1->yMax; } break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) { TextLineFrag *frag1 = (TextLineFrag *)p1; TextLineFrag *frag2 = (TextLineFrag *)p2; double cmp; cmp = 0; // make gcc happy switch (frag1->line->rot) { case 0: if ((cmp = frag1->xMin - frag2->xMin) == 0) { cmp = frag1->yMin - frag2->yMin; } break; case 1: if ((cmp = frag1->yMin - frag2->yMin) == 0) { cmp = frag2->xMax - frag1->xMax; } break; case 2: if ((cmp = frag2->xMax - frag1->xMax) == 0) { cmp = frag2->yMin - frag1->yMin; } break; case 3: if ((cmp = frag2->yMax - frag1->yMax) == 0) { cmp = frag1->xMax - frag2->xMax; } break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextLineFrag::cmpXYColumnPrimaryRot(const void *p1, const void *p2) { TextLineFrag *frag1 = (TextLineFrag *)p1; TextLineFrag *frag2 = (TextLineFrag *)p2; double cmp; // if columns overlap, compare y values if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] - frag2->line->col[frag2->start]) && frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start])) { cmp = 0; // make gcc happy switch (frag1->line->blk->page->primaryRot) { case 0: cmp = frag1->yMin - frag2->yMin; break; case 1: cmp = frag2->xMax - frag1->xMax; break; case 2: cmp = frag2->yMin - frag1->yMin; break; case 3: cmp = frag1->xMax - frag2->xMax; break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } // otherwise, compare starting column return frag1->col - frag2->col; } int TextLineFrag::cmpXYColumnLineRot(const void *p1, const void *p2) { TextLineFrag *frag1 = (TextLineFrag *)p1; TextLineFrag *frag2 = (TextLineFrag *)p2; double cmp; // if columns overlap, compare y values if (frag1->col < frag2->col + (frag2->line->col[frag2->start + frag2->len] - frag2->line->col[frag2->start]) && frag2->col < frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start])) { cmp = 0; // make gcc happy switch (frag1->line->rot) { case 0: cmp = frag1->yMin - frag2->yMin; break; case 1: cmp = frag2->xMax - frag1->xMax; break; case 2: cmp = frag2->yMin - frag1->yMin; break; case 3: cmp = frag1->xMax - frag2->xMax; break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } // otherwise, compare starting column return frag1->col - frag2->col; } //------------------------------------------------------------------------ // TextBlock //------------------------------------------------------------------------ TextBlock::TextBlock(TextPage *pageA, int rotA) { page = pageA; rot = rotA; xMin = yMin = 0; xMax = yMax = -1; priMin = 0; priMax = page->pageWidth; pool = new TextPool(); lines = NULL; curLine = NULL; next = NULL; stackNext = NULL; } TextBlock::~TextBlock() { TextLine *line; delete pool; while (lines) { line = lines; lines = lines->next; delete line; } } void TextBlock::addWord(TextWord *word) { pool->addWord(word); if (xMin > xMax) { xMin = word->xMin; xMax = word->xMax; yMin = word->yMin; yMax = word->yMax; } else { if (word->xMin < xMin) { xMin = word->xMin; } if (word->xMax > xMax) { xMax = word->xMax; } if (word->yMin < yMin) { yMin = word->yMin; } if (word->yMax > yMax) { yMax = word->yMax; } } } void TextBlock::coalesce(UnicodeMap *uMap, double fixedPitch) { TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord; TextLine *line, *line0, *line1; int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx; int baseIdx, bestWordBaseIdx, idx0, idx1; double minBase, maxBase; double fontSize, wordSpacing, delta, priDelta, secDelta; TextLine **lineArray; GBool found, overlap; int col1, col2; int i, j, k; // discard duplicated text (fake boldface, drop shadows) for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) { word0 = pool->getPool(idx0); while (word0) { priDelta = dupMaxPriDelta * word0->fontSize; secDelta = dupMaxSecDelta * word0->fontSize; maxBaseIdx = pool->getBaseIdx(word0->base + secDelta); found = gFalse; word1 = word2 = NULL; // make gcc happy for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) { if (idx1 == idx0) { word1 = word0; word2 = word0->next; } else { word1 = NULL; word2 = pool->getPool(idx1); } for (; word2; word1 = word2, word2 = word2->next) { if (word2->len == word0->len && !memcmp(word2->text, word0->text, word0->len * sizeof(Unicode))) { switch (rot) { case 0: case 2: found = fabs(word0->xMin - word2->xMin) < priDelta && fabs(word0->xMax - word2->xMax) < priDelta && fabs(word0->yMin - word2->yMin) < secDelta && fabs(word0->yMax - word2->yMax) < secDelta; break; case 1: case 3: found = fabs(word0->xMin - word2->xMin) < secDelta && fabs(word0->xMax - word2->xMax) < secDelta && fabs(word0->yMin - word2->yMin) < priDelta && fabs(word0->yMax - word2->yMax) < priDelta; break; } } if (found) { break; } } if (found) { break; } } if (found) { if (word1) { word1->next = word2->next; } else { pool->setPool(idx1, word2->next); } delete word2; } else { word0 = word0->next; } } } // build the lines curLine = NULL; poolMinBaseIdx = pool->minBaseIdx; charCount = 0; nLines = 0; while (1) { // find the first non-empty line in the pool for (; poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx); ++poolMinBaseIdx) ; if (poolMinBaseIdx > pool->maxBaseIdx) { break; } // look for the left-most word in the first four lines of the // pool -- this avoids starting with a superscript word startBaseIdx = poolMinBaseIdx; for (baseIdx = poolMinBaseIdx + 1; baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; ++baseIdx) { if (!pool->getPool(baseIdx)) { continue; } if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) < 0) { startBaseIdx = baseIdx; } } // create a new line word0 = pool->getPool(startBaseIdx); pool->setPool(startBaseIdx, word0->next); word0->next = NULL; line = new TextLine(this, word0->rot, word0->base); line->addWord(word0); lastWord = word0; // compute the search range fontSize = word0->fontSize; minBase = word0->base - maxIntraLineDelta * fontSize; maxBase = word0->base + maxIntraLineDelta * fontSize; minBaseIdx = pool->getBaseIdx(minBase); maxBaseIdx = pool->getBaseIdx(maxBase); wordSpacing = fixedPitch ? fixedPitch : maxWordSpacing * fontSize; // find the rest of the words in this line while (1) { // find the left-most word whose baseline is in the range for // this line bestWordBaseIdx = 0; bestWord0 = bestWord1 = NULL; overlap = gFalse; for (baseIdx = minBaseIdx; !overlap && baseIdx <= maxBaseIdx; ++baseIdx) { for (word0 = NULL, word1 = pool->getPool(baseIdx); word1; word0 = word1, word1 = word1->next) { if (word1->base >= minBase && word1->base <= maxBase) { delta = lastWord->primaryDelta(word1); if (delta < minCharSpacing * fontSize) { overlap = gTrue; break; } else { if (delta < wordSpacing && (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) { bestWordBaseIdx = baseIdx; bestWord0 = word0; bestWord1 = word1; } break; } } } } if (overlap || !bestWord1) { break; } // remove it from the pool, and add it to the line if (bestWord0) { bestWord0->next = bestWord1->next; } else { pool->setPool(bestWordBaseIdx, bestWord1->next); } bestWord1->next = NULL; line->addWord(bestWord1); lastWord = bestWord1; } // add the line if (curLine && line->cmpYX(curLine) > 0) { line0 = curLine; line1 = curLine->next; } else { line0 = NULL; line1 = lines; } for (; line1 && line->cmpYX(line1) > 0; line0 = line1, line1 = line1->next) ; if (line0) { line0->next = line; } else { lines = line; } line->next = line1; curLine = line; line->coalesce(uMap); charCount += line->len; ++nLines; } // sort lines into xy order for column assignment lineArray = (TextLine **)gmallocn(nLines, sizeof(TextLine *)); for (line = lines, i = 0; line; line = line->next, ++i) { lineArray[i] = line; } qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY); // column assignment nColumns = 0; if (fixedPitch) { for (i = 0; i < nLines; ++i) { line0 = lineArray[i]; col1 = 0; // make gcc happy switch (rot) { case 0: col1 = (int)((line0->xMin - xMin) / fixedPitch + 0.5); break; case 1: col1 = (int)((line0->yMin - yMin) / fixedPitch + 0.5); break; case 2: col1 = (int)((xMax - line0->xMax) / fixedPitch + 0.5); break; case 3: col1 = (int)((yMax - line0->yMax) / fixedPitch + 0.5); break; } for (k = 0; k <= line0->len; ++k) { line0->col[k] += col1; } if (line0->col[line0->len] > nColumns) { nColumns = line0->col[line0->len]; } } } else { for (i = 0; i < nLines; ++i) { line0 = lineArray[i]; col1 = 0; for (j = 0; j < i; ++j) { line1 = lineArray[j]; if (line1->primaryDelta(line0) >= 0) { col2 = line1->col[line1->len] + 1; } else { k = 0; // make gcc happy switch (rot) { case 0: for (k = 0; k < line1->len && line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); ++k) ; break; case 1: for (k = 0; k < line1->len && line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]); ++k) ; break; case 2: for (k = 0; k < line1->len && line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); ++k) ; break; case 3: for (k = 0; k < line1->len && line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]); ++k) ; break; } col2 = line1->col[k]; } if (col2 > col1) { col1 = col2; } } for (k = 0; k <= line0->len; ++k) { line0->col[k] += col1; } if (line0->col[line0->len] > nColumns) { nColumns = line0->col[line0->len]; } } } gfree(lineArray); } void TextBlock::updatePriMinMax(TextBlock *blk) { double newPriMin, newPriMax; GBool gotPriMin, gotPriMax; gotPriMin = gotPriMax = gFalse; newPriMin = newPriMax = 0; // make gcc happy switch (page->primaryRot) { case 0: case 2: if (blk->yMin < yMax && blk->yMax > yMin) { if (blk->xMin < xMin) { newPriMin = blk->xMax; gotPriMin = gTrue; } if (blk->xMax > xMax) { newPriMax = blk->xMin; gotPriMax = gTrue; } } break; case 1: case 3: if (blk->xMin < xMax && blk->xMax > xMin) { if (blk->yMin < yMin) { newPriMin = blk->yMax; gotPriMin = gTrue; } if (blk->yMax > yMax) { newPriMax = blk->yMin; gotPriMax = gTrue; } } break; } if (gotPriMin) { if (newPriMin > xMin) { newPriMin = xMin; } if (newPriMin > priMin) { priMin = newPriMin; } } if (gotPriMax) { if (newPriMax < xMax) { newPriMax = xMax; } if (newPriMax < priMax) { priMax = newPriMax; } } } int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) { TextBlock *blk1 = *(TextBlock **)p1; TextBlock *blk2 = *(TextBlock **)p2; double cmp; cmp = 0; // make gcc happy switch (blk1->page->primaryRot) { case 0: if ((cmp = blk1->xMin - blk2->xMin) == 0) { cmp = blk1->yMin - blk2->yMin; } break; case 1: if ((cmp = blk1->yMin - blk2->yMin) == 0) { cmp = blk2->xMax - blk1->xMax; } break; case 2: if ((cmp = blk2->xMax - blk1->xMax) == 0) { cmp = blk2->yMin - blk1->yMin; } break; case 3: if ((cmp = blk2->yMax - blk1->yMax) == 0) { cmp = blk1->xMax - blk2->xMax; } break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) { TextBlock *blk1 = *(TextBlock **)p1; TextBlock *blk2 = *(TextBlock **)p2; double cmp; cmp = 0; // make gcc happy switch (blk1->page->primaryRot) { case 0: if ((cmp = blk1->yMin - blk2->yMin) == 0) { cmp = blk1->xMin - blk2->xMin; } break; case 1: if ((cmp = blk2->xMax - blk1->xMax) == 0) { cmp = blk1->yMin - blk2->yMin; } break; case 2: if ((cmp = blk2->yMin - blk1->yMin) == 0) { cmp = blk2->xMax - blk1->xMax; } break; case 3: if ((cmp = blk1->xMax - blk2->xMax) == 0) { cmp = blk2->yMax - blk1->yMax; } break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } int TextBlock::primaryCmp(TextBlock *blk) { double cmp; cmp = 0; // make gcc happy switch (rot) { case 0: cmp = xMin - blk->xMin; break; case 1: cmp = yMin - blk->yMin; break; case 2: cmp = blk->xMax - xMax; break; case 3: cmp = blk->yMax - yMax; break; } return cmp < 0 ? -1 : cmp > 0 ? 1 : 0; } double TextBlock::secondaryDelta(TextBlock *blk) { double delta; delta = 0; // make gcc happy switch (rot) { case 0: delta = blk->yMin - yMax; break; case 1: delta = xMin - blk->xMax; break; case 2: delta = yMin - blk->yMax; break; case 3: delta = blk->xMin - xMax; break; } return delta; } GBool TextBlock::isBelow(TextBlock *blk) { GBool below; below = gFalse; // make gcc happy switch (page->primaryRot) { case 0: below = xMin >= blk->priMin && xMax <= blk->priMax && yMin > blk->yMin; break; case 1: below = yMin >= blk->priMin && yMax <= blk->priMax && xMax < blk->xMax; break; case 2: below = xMin >= blk->priMin && xMax <= blk->priMax && yMax < blk->yMax; break; case 3: below = yMin >= blk->priMin && yMax <= blk->priMax && xMin > blk->xMin; break; } return below; } //------------------------------------------------------------------------ // TextFlow //------------------------------------------------------------------------ TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) { page = pageA; xMin = blk->xMin; xMax = blk->xMax; yMin = blk->yMin; yMax = blk->yMax; priMin = blk->priMin; priMax = blk->priMax; blocks = lastBlk = blk; next = NULL; } TextFlow::~TextFlow() { TextBlock *blk; while (blocks) { blk = blocks; blocks = blocks->next; delete blk; } } void TextFlow::addBlock(TextBlock *blk) { if (lastBlk) { lastBlk->next = blk; } else { blocks = blk; } lastBlk = blk; if (blk->xMin < xMin) { xMin = blk->xMin; } if (blk->xMax > xMax) { xMax = blk->xMax; } if (blk->yMin < yMin) { yMin = blk->yMin; } if (blk->yMax > yMax) { yMax = blk->yMax; } } GBool TextFlow::blockFits(TextBlock *blk, TextBlock *prevBlk) { GBool fits; // lower blocks must use smaller fonts if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) { return gFalse; } fits = gFalse; // make gcc happy switch (page->primaryRot) { case 0: fits = blk->xMin >= priMin && blk->xMax <= priMax; break; case 1: fits = blk->yMin >= priMin && blk->yMax <= priMax; break; case 2: fits = blk->xMin >= priMin && blk->xMax <= priMax; break; case 3: fits = blk->yMin >= priMin && blk->yMax <= priMax; break; } return fits; } #if TEXTOUT_WORD_LIST //------------------------------------------------------------------------ // TextWordList //------------------------------------------------------------------------ TextWordList::TextWordList(TextPage *text, GBool physLayout) { TextFlow *flow; TextBlock *blk; TextLine *line; TextWord *word; TextWord **wordArray; int nWords, i; words = new GList(); if (text->rawOrder) { for (word = text->rawWords; word; word = word->next) { words->append(word); } } else if (physLayout) { // this is inefficient, but it's also the least useful of these // three cases nWords = 0; for (flow = text->flows; flow; flow = flow->next) { for (blk = flow->blocks; blk; blk = blk->next) { for (line = blk->lines; line; line = line->next) { for (word = line->words; word; word = word->next) { ++nWords; } } } } wordArray = (TextWord **)gmallocn(nWords, sizeof(TextWord *)); i = 0; for (flow = text->flows; flow; flow = flow->next) { for (blk = flow->blocks; blk; blk = blk->next) { for (line = blk->lines; line; line = line->next) { for (word = line->words; word; word = word->next) { wordArray[i++] = word; } } } } qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX); for (i = 0; i < nWords; ++i) { words->append(wordArray[i]); } gfree(wordArray); } else { for (flow = text->flows; flow; flow = flow->next) { for (blk = flow->blocks; blk; blk = blk->next) { for (line = blk->lines; line; line = line->next) { for (word = line->words; word; word = word->next) { words->append(word); } } } } } } TextWordList::~TextWordList() { delete words; } int TextWordList::getLength() { return words->getLength(); } TextWord *TextWordList::get(int idx) { if (idx < 0 || idx >= words->getLength()) { return NULL; } return (TextWord *)words->get(idx); } #endif // TEXTOUT_WORD_LIST //------------------------------------------------------------------------ // TextPage //------------------------------------------------------------------------ TextPage::TextPage(GBool rawOrderA) { int rot; rawOrder = rawOrderA; curWord = NULL; charPos = 0; curFont = NULL; curFontSize = 0; nest = 0; nTinyChars = 0; lastCharOverlap = gFalse; actualText = NULL; actualTextLen = 0; actualTextNBytes = 0; if (!rawOrder) { for (rot = 0; rot < 4; ++rot) { pools[rot] = new TextPool(); } } flows = NULL; blocks = NULL; rawWords = NULL; rawLastWord = NULL; fonts = new GList(); lastFindXMin = lastFindYMin = 0; haveLastFind = gFalse; underlines = new GList(); links = new GList(); } TextPage::~TextPage() { int rot; clear(); if (!rawOrder) { for (rot = 0; rot < 4; ++rot) { delete pools[rot]; } } delete fonts; deleteGList(underlines, TextUnderline); deleteGList(links, TextLink); } void TextPage::startPage(GfxState *state) { clear(); if (state) { pageWidth = state->getPageWidth(); pageHeight = state->getPageHeight(); } else { pageWidth = pageHeight = 0; } } void TextPage::endPage() { if (curWord) { endWord(); } } void TextPage::clear() { int rot; TextFlow *flow; TextWord *word; if (curWord) { delete curWord; curWord = NULL; } gfree(actualText); if (rawOrder) { while (rawWords) { word = rawWords; rawWords = rawWords->next; delete word; } } else { for (rot = 0; rot < 4; ++rot) { delete pools[rot]; } while (flows) { flow = flows; flows = flows->next; delete flow; } gfree(blocks); } deleteGList(fonts, TextFontInfo); deleteGList(underlines, TextUnderline); deleteGList(links, TextLink); curWord = NULL; charPos = 0; curFont = NULL; curFontSize = 0; nest = 0; nTinyChars = 0; actualText = NULL; actualTextLen = 0; actualTextNBytes = 0; if (!rawOrder) { for (rot = 0; rot < 4; ++rot) { pools[rot] = new TextPool(); } } flows = NULL; blocks = NULL; rawWords = NULL; rawLastWord = NULL; fonts = new GList(); underlines = new GList(); links = new GList(); } void TextPage::updateFont(GfxState *state) { GfxFont *gfxFont; double *fm; char *name; int code, mCode, letterCode, anyCode; double w; int i; // get the font info object curFont = NULL; for (i = 0; i < fonts->getLength(); ++i) { curFont = (TextFontInfo *)fonts->get(i); if (curFont->matches(state)) { break; } curFont = NULL; } if (!curFont) { curFont = new TextFontInfo(state); fonts->append(curFont); } // adjust the font size gfxFont = state->getFont(); curFontSize = state->getTransformedFontSize(); if (gfxFont && gfxFont->getType() == fontType3) { // This is a hack which makes it possible to deal with some Type 3 // fonts. The problem is that it's impossible to know what the // base coordinate system used in the font is without actually // rendering the font. This code tries to guess by looking at the // width of the character 'm' (which breaks if the font is a // subset that doesn't contain 'm'). mCode = letterCode = anyCode = -1; for (code = 0; code < 256; ++code) { name = ((Gfx8BitFont *)gfxFont)->getCharName(code); if (name && name[0] == 'm' && name[1] == '\0') { mCode = code; } if (letterCode < 0 && name && name[1] == '\0' && ((name[0] >= 'A' && name[0] <= 'Z') || (name[0] >= 'a' && name[0] <= 'z'))) { letterCode = code; } if (anyCode < 0 && name && ((Gfx8BitFont *)gfxFont)->getWidth(code) > 0) { anyCode = code; } } if (mCode >= 0 && (w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) { // 0.6 is a generic average 'm' width -- yes, this is a hack curFontSize *= w / 0.6; } else if (letterCode >= 0 && (w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) { // even more of a hack: 0.5 is a generic letter width curFontSize *= w / 0.5; } else if (anyCode >= 0 && (w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) { // better than nothing: 0.5 is a generic character width curFontSize *= w / 0.5; } fm = gfxFont->getFontMatrix(); if (fm[0] != 0) { curFontSize *= fabs(fm[3] / fm[0]); } } } void TextPage::beginWord(GfxState *state, double x0, double y0) { double *fontm; double m[4], m2[4]; int rot; // This check is needed because Type 3 characters can contain // text-drawing operations (when TextPage is being used via // {X,Win}SplashOutputDev rather than TextOutputDev). if (curWord) { ++nest; return; } // compute the rotation state->getFontTransMat(&m[0], &m[1], &m[2], &m[3]); if (state->getFont()->getType() == fontType3) { fontm = state->getFont()->getFontMatrix(); m2[0] = fontm[0] * m[0] + fontm[1] * m[2]; m2[1] = fontm[0] * m[1] + fontm[1] * m[3]; m2[2] = fontm[2] * m[0] + fontm[3] * m[2]; m2[3] = fontm[2] * m[1] + fontm[3] * m[3]; m[0] = m2[0]; m[1] = m2[1]; m[2] = m2[2]; m[3] = m2[3]; } if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) { rot = (m[0] > 0 || m[3] < 0) ? 0 : 2; } else { rot = (m[2] > 0) ? 1 : 3; } // for vertical writing mode, the lines are effectively rotated 90 // degrees if (state->getFont()->getWMode()) { rot = (rot + 1) & 3; } curWord = new TextWord(state, rot, x0, y0, curFont, curFontSize); } void TextPage::addChar(GfxState *state, double x, double y, double dx, double dy, CharCode c, int nBytes, Unicode *u, int uLen) { double x1, y1, w1, h1, dx2, dy2, base, sp, delta; GBool overlap; int i; // if we're in an ActualText span, save the position info (the // ActualText chars will be added by TextPage::endActualText()). if (actualText) { if (!actualTextNBytes) { actualTextX0 = x; actualTextY0 = y; } actualTextX1 = x + dx; actualTextY1 = y + dy; actualTextNBytes += nBytes; return; } // subtract char and word spacing from the dx,dy values sp = state->getCharSpace(); if (c == (CharCode)0x20) { sp += state->getWordSpace(); } state->textTransformDelta(sp * state->getHorizScaling(), 0, &dx2, &dy2); dx -= dx2; dy -= dy2; state->transformDelta(dx, dy, &w1, &h1); // throw away chars that aren't inside the page bounds // (and also do a sanity check on the character size) state->transform(x, y, &x1, &y1); if (x1 + w1 < 0 || x1 > pageWidth || y1 + h1 < 0 || y1 > pageHeight || w1 > pageWidth || h1 > pageHeight) { charPos += nBytes; return; } // check the tiny chars limit if (!globalParams->getTextKeepTinyChars() && fabs(w1) < 3 && fabs(h1) < 3) { if (++nTinyChars > 50000) { charPos += nBytes; return; } } // break words at space character if (uLen == 1 && u[0] == (Unicode)0x20) { charPos += nBytes; endWord(); return; } // start a new word if: // (1) this character doesn't fall in the right place relative to // the end of the previous word (this places upper and lower // constraints on the position deltas along both the primary // and secondary axes), or // (2) this character overlaps the previous one (duplicated text), or // (3) the previous character was an overlap (we want each duplicated // character to be in a word by itself at this stage), // (4) the font or font size has changed if (curWord && curWord->len > 0) { base = sp = delta = 0; // make gcc happy switch (curWord->rot) { case 0: base = y1; sp = x1 - curWord->xMax; delta = x1 - curWord->edge[curWord->len - 1]; break; case 1: base = x1; sp = y1 - curWord->yMax; delta = y1 - curWord->edge[curWord->len - 1]; break; case 2: base = y1; sp = curWord->xMin - x1; delta = curWord->edge[curWord->len - 1] - x1; break; case 3: base = x1; sp = curWord->yMin - y1; delta = curWord->edge[curWord->len - 1] - y1; break; } overlap = fabs(delta) < dupMaxPriDelta * curWord->fontSize && fabs(base - curWord->base) < dupMaxSecDelta * curWord->fontSize; if (overlap || lastCharOverlap || sp < -minDupBreakOverlap * curWord->fontSize || sp > minWordBreakSpace * curWord->fontSize || fabs(base - curWord->base) > 0.5 || curFont != curWord->font || curFontSize != curWord->fontSize) { endWord(); } lastCharOverlap = overlap; } else { lastCharOverlap = gFalse; } if (uLen != 0) { // start a new word if needed if (!curWord) { beginWord(state, x, y); } // page rotation and/or transform matrices can cause text to be // drawn in reverse order -- in this case, swap the begin/end // coordinates and break text into individual chars if ((curWord->rot == 0 && w1 < 0) || (curWord->rot == 1 && h1 < 0) || (curWord->rot == 2 && w1 > 0) || (curWord->rot == 3 && h1 > 0)) { endWord(); beginWord(state, x + dx, y + dy); x1 += w1; y1 += h1; w1 = -w1; h1 = -h1; } // add the characters to the current word w1 /= uLen; h1 /= uLen; for (i = 0; i < uLen; ++i) { curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, charPos, nBytes, u[i]); } } charPos += nBytes; } void TextPage::incCharCount(int nChars) { charPos += nChars; } void TextPage::beginActualText(GfxState *state, Unicode *u, int uLen) { if (actualText) { gfree(actualText); } actualText = (Unicode *)gmallocn(uLen, sizeof(Unicode)); memcpy(actualText, u, uLen * sizeof(Unicode)); actualTextLen = uLen; actualTextNBytes = 0; } void TextPage::endActualText(GfxState *state) { Unicode *u; u = actualText; actualText = NULL; // so we can call TextPage::addChar() if (actualTextNBytes) { // now that we have the position info for all of the text inside // the marked content span, we feed the "ActualText" back through // addChar() addChar(state, actualTextX0, actualTextY0, actualTextX1 - actualTextX0, actualTextY1 - actualTextY0, 0, actualTextNBytes, u, actualTextLen); } gfree(u); actualText = NULL; actualTextLen = 0; actualTextNBytes = gFalse; } void TextPage::endWord() { // This check is needed because Type 3 characters can contain // text-drawing operations (when TextPage is being used via // {X,Win}SplashOutputDev rather than TextOutputDev). if (nest > 0) { --nest; return; } if (curWord) { addWord(curWord); curWord = NULL; } } void TextPage::addWord(TextWord *word) { // throw away zero-length words -- they don't have valid xMin/xMax // values, and they're useless anyway if (word->len == 0) { delete word; return; } if (rawOrder) { if (rawLastWord) { rawLastWord->next = word; } else { rawWords = word; } rawLastWord = word; } else { pools[word->rot]->addWord(word); } } void TextPage::addUnderline(double x0, double y0, double x1, double y1) { underlines->append(new TextUnderline(x0, y0, x1, y1)); } void TextPage::addLink(int xMin, int yMin, int xMax, int yMax, Link *link) { links->append(new TextLink(xMin, yMin, xMax, yMax, link)); } void TextPage::coalesce(GBool physLayout, double fixedPitch, GBool doHTML) { UnicodeMap *uMap; TextPool *pool; TextWord *word0, *word1, *word2; TextLine *line; TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1; TextBlock **blkArray; TextFlow *flow, *lastFlow; TextUnderline *underline; TextLink *link; int rot, poolMinBaseIdx, baseIdx, startBaseIdx, endBaseIdx; double minBase, maxBase, newMinBase, newMaxBase; double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace; GBool found; int count[4]; int lrCount; int firstBlkIdx, nBlocksLeft; int col1, col2; int i, j, n; if (rawOrder) { primaryRot = 0; primaryLR = gTrue; return; } uMap = globalParams->getTextEncoding(); blkList = NULL; lastBlk = NULL; nBlocks = 0; primaryRot = 0; #if 0 // for debugging printf("*** initial words ***\n"); for (rot = 0; rot < 4; ++rot) { pool = pools[rot]; for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) { for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) { printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f rot=%d link=%p '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->base, word0->fontSize, rot*90, word0->link); for (i = 0; i < word0->len; ++i) { fputc(word0->text[i] & 0xff, stdout); } printf("'\n"); } } } printf("\n"); #endif #if 0 //~ for debugging for (i = 0; i < underlines->getLength(); ++i) { underline = (TextUnderline *)underlines->get(i); printf("underline: x=%g..%g y=%g..%g horiz=%d\n", underline->x0, underline->x1, underline->y0, underline->y1, underline->horiz); } #endif if (doHTML) { //----- handle underlining for (i = 0; i < underlines->getLength(); ++i) { underline = (TextUnderline *)underlines->get(i); if (underline->horiz) { // rot = 0 if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) { startBaseIdx = pools[0]->getBaseIdx(underline->y0 + minUnderlineGap); endBaseIdx = pools[0]->getBaseIdx(underline->y0 + maxUnderlineGap); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) { //~ need to check the y value against the word baseline if (underline->x0 < word0->xMin + underlineSlack && word0->xMax - underlineSlack < underline->x1) { word0->underlined = gTrue; } } } } // rot = 2 if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) { startBaseIdx = pools[2]->getBaseIdx(underline->y0 - maxUnderlineGap); endBaseIdx = pools[2]->getBaseIdx(underline->y0 - minUnderlineGap); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) { if (underline->x0 < word0->xMin + underlineSlack && word0->xMax - underlineSlack < underline->x1) { word0->underlined = gTrue; } } } } } else { // rot = 1 if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) { startBaseIdx = pools[1]->getBaseIdx(underline->x0 - maxUnderlineGap); endBaseIdx = pools[1]->getBaseIdx(underline->x0 - minUnderlineGap); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) { if (underline->y0 < word0->yMin + underlineSlack && word0->yMax - underlineSlack < underline->y1) { word0->underlined = gTrue; } } } } // rot = 3 if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) { startBaseIdx = pools[3]->getBaseIdx(underline->x0 + minUnderlineGap); endBaseIdx = pools[3]->getBaseIdx(underline->x0 + maxUnderlineGap); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) { if (underline->y0 < word0->yMin + underlineSlack && word0->yMax - underlineSlack < underline->y1) { word0->underlined = gTrue; } } } } } } //----- handle links for (i = 0; i < links->getLength(); ++i) { link = (TextLink *)links->get(i); // rot = 0 if (pools[0]->minBaseIdx <= pools[0]->maxBaseIdx) { startBaseIdx = pools[0]->getBaseIdx(link->yMin); endBaseIdx = pools[0]->getBaseIdx(link->yMax); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[0]->getPool(j); word0; word0 = word0->next) { if (link->xMin < word0->xMin + hyperlinkSlack && word0->xMax - hyperlinkSlack < link->xMax && link->yMin < word0->yMin + hyperlinkSlack && word0->yMax - hyperlinkSlack < link->yMax) { word0->link = link->link; } } } } // rot = 2 if (pools[2]->minBaseIdx <= pools[2]->maxBaseIdx) { startBaseIdx = pools[2]->getBaseIdx(link->yMin); endBaseIdx = pools[2]->getBaseIdx(link->yMax); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[2]->getPool(j); word0; word0 = word0->next) { if (link->xMin < word0->xMin + hyperlinkSlack && word0->xMax - hyperlinkSlack < link->xMax && link->yMin < word0->yMin + hyperlinkSlack && word0->yMax - hyperlinkSlack < link->yMax) { word0->link = link->link; } } } } // rot = 1 if (pools[1]->minBaseIdx <= pools[1]->maxBaseIdx) { startBaseIdx = pools[1]->getBaseIdx(link->xMin); endBaseIdx = pools[1]->getBaseIdx(link->xMax); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[1]->getPool(j); word0; word0 = word0->next) { if (link->yMin < word0->yMin + hyperlinkSlack && word0->yMax - hyperlinkSlack < link->yMax && link->xMin < word0->xMin + hyperlinkSlack && word0->xMax - hyperlinkSlack < link->xMax) { word0->link = link->link; } } } } // rot = 3 if (pools[3]->minBaseIdx <= pools[3]->maxBaseIdx) { startBaseIdx = pools[3]->getBaseIdx(link->xMin); endBaseIdx = pools[3]->getBaseIdx(link->xMax); for (j = startBaseIdx; j <= endBaseIdx; ++j) { for (word0 = pools[3]->getPool(j); word0; word0 = word0->next) { if (link->yMin < word0->yMin + hyperlinkSlack && word0->yMax - hyperlinkSlack < link->yMax && link->xMin < word0->xMin + hyperlinkSlack && word0->xMax - hyperlinkSlack < link->xMax) { word0->link = link->link; } } } } } } //----- assemble the blocks //~ add an outer loop for writing mode (vertical text) // build blocks for each rotation value for (rot = 0; rot < 4; ++rot) { pool = pools[rot]; poolMinBaseIdx = pool->minBaseIdx; count[rot] = 0; // add blocks until no more words are left while (1) { // find the first non-empty line in the pool for (; poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx); ++poolMinBaseIdx) ; if (poolMinBaseIdx > pool->maxBaseIdx) { break; } // look for the left-most word in the first four lines of the // pool -- this avoids starting with a superscript word startBaseIdx = poolMinBaseIdx; for (baseIdx = poolMinBaseIdx + 1; baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx; ++baseIdx) { if (!pool->getPool(baseIdx)) { continue; } if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx)) < 0) { startBaseIdx = baseIdx; } } // create a new block word0 = pool->getPool(startBaseIdx); pool->setPool(startBaseIdx, word0->next); word0->next = NULL; blk = new TextBlock(this, rot); blk->addWord(word0); fontSize = word0->fontSize; minBase = maxBase = word0->base; colSpace1 = minColSpacing1 * fontSize; colSpace2 = minColSpacing2 * fontSize; lineSpace = maxLineSpacingDelta * fontSize; intraLineSpace = maxIntraLineDelta * fontSize; // add words to the block do { found = gFalse; // look for words on the line above the current top edge of // the block newMinBase = minBase; for (baseIdx = pool->getBaseIdx(minBase); baseIdx >= pool->getBaseIdx(minBase - lineSpace); --baseIdx) { word0 = NULL; word1 = pool->getPool(baseIdx); while (word1) { if (word1->base < minBase && word1->base >= minBase - lineSpace && ((rot == 0 || rot == 2) ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta1 * fontSize) { word2 = word1; if (word0) { word0->next = word1->next; } else { pool->setPool(baseIdx, word1->next); } word1 = word1->next; word2->next = NULL; blk->addWord(word2); found = gTrue; newMinBase = word2->base; } else { word0 = word1; word1 = word1->next; } } } minBase = newMinBase; // look for words on the line below the current bottom edge of // the block newMaxBase = maxBase; for (baseIdx = pool->getBaseIdx(maxBase); baseIdx <= pool->getBaseIdx(maxBase + lineSpace); ++baseIdx) { word0 = NULL; word1 = pool->getPool(baseIdx); while (word1) { if (word1->base > maxBase && word1->base <= maxBase + lineSpace && ((rot == 0 || rot == 2) ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta1 * fontSize) { word2 = word1; if (word0) { word0->next = word1->next; } else { pool->setPool(baseIdx, word1->next); } word1 = word1->next; word2->next = NULL; blk->addWord(word2); found = gTrue; newMaxBase = word2->base; } else { word0 = word1; word1 = word1->next; } } } maxBase = newMaxBase; // look for words that are on lines already in the block, and // that overlap the block horizontally for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); ++baseIdx) { word0 = NULL; word1 = pool->getPool(baseIdx); while (word1) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMin < blk->xMax + colSpace1 && word1->xMax > blk->xMin - colSpace1) : (word1->yMin < blk->yMax + colSpace1 && word1->yMax > blk->yMin - colSpace1)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta2 * fontSize) { word2 = word1; if (word0) { word0->next = word1->next; } else { pool->setPool(baseIdx, word1->next); } word1 = word1->next; word2->next = NULL; blk->addWord(word2); found = gTrue; } else { word0 = word1; word1 = word1->next; } } } // only check for outlying words (the next two chunks of code) // if we didn't find anything else if (found) { continue; } // scan down the left side of the block, looking for words // that are near (but not overlapping) the block; if there are // three or fewer, add them to the block n = 0; for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); ++baseIdx) { word1 = pool->getPool(baseIdx); while (word1) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMax <= blk->xMin && word1->xMax > blk->xMin - colSpace2) : (word1->yMax <= blk->yMin && word1->yMax > blk->yMin - colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { ++n; break; } word1 = word1->next; } } if (n > 0 && n <= 3) { for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); ++baseIdx) { word0 = NULL; word1 = pool->getPool(baseIdx); while (word1) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMax <= blk->xMin && word1->xMax > blk->xMin - colSpace2) : (word1->yMax <= blk->yMin && word1->yMax > blk->yMin - colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { word2 = word1; if (word0) { word0->next = word1->next; } else { pool->setPool(baseIdx, word1->next); } word1 = word1->next; word2->next = NULL; blk->addWord(word2); if (word2->base < minBase) { minBase = word2->base; } else if (word2->base > maxBase) { maxBase = word2->base; } found = gTrue; break; } else { word0 = word1; word1 = word1->next; } } } } // scan down the right side of the block, looking for words // that are near (but not overlapping) the block; if there are // three or fewer, add them to the block n = 0; for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); ++baseIdx) { word1 = pool->getPool(baseIdx); while (word1) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMin >= blk->xMax && word1->xMin < blk->xMax + colSpace2) : (word1->yMin >= blk->yMax && word1->yMin < blk->yMax + colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { ++n; break; } word1 = word1->next; } } if (n > 0 && n <= 3) { for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace); baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace); ++baseIdx) { word0 = NULL; word1 = pool->getPool(baseIdx); while (word1) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMin >= blk->xMax && word1->xMin < blk->xMax + colSpace2) : (word1->yMin >= blk->yMax && word1->yMin < blk->yMax + colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { word2 = word1; if (word0) { word0->next = word1->next; } else { pool->setPool(baseIdx, word1->next); } word1 = word1->next; word2->next = NULL; blk->addWord(word2); if (word2->base < minBase) { minBase = word2->base; } else if (word2->base > maxBase) { maxBase = word2->base; } found = gTrue; break; } else { word0 = word1; word1 = word1->next; } } } } } while (found); //~ need to compute the primary writing mode (horiz/vert) in //~ addition to primary rotation // coalesce the block, and add it to the list blk->coalesce(uMap, fixedPitch); if (lastBlk) { lastBlk->next = blk; } else { blkList = blk; } lastBlk = blk; count[rot] += blk->charCount; ++nBlocks; } if (count[rot] > count[primaryRot]) { primaryRot = rot; } } #if 0 // for debugging printf("*** rotation ***\n"); for (rot = 0; rot < 4; ++rot) { printf(" %d: %6d\n", rot, count[rot]); } printf(" primary rot = %d\n", primaryRot); printf("\n"); #endif #if 0 // for debugging printf("*** blocks ***\n"); for (blk = blkList; blk; blk = blk->next) { printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n", blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax); for (line = blk->lines; line; line = line->next) { printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n", line->xMin, line->xMax, line->yMin, line->yMax, line->base); for (word0 = line->words; word0; word0 = word0->next) { printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->base, word0->fontSize, word0->spaceAfter); for (i = 0; i < word0->len; ++i) { fputc(word0->text[i] & 0xff, stdout); } printf("'\n"); } } } printf("\n"); #endif // determine the primary direction lrCount = 0; for (blk = blkList; blk; blk = blk->next) { for (line = blk->lines; line; line = line->next) { for (word0 = line->words; word0; word0 = word0->next) { for (i = 0; i < word0->len; ++i) { if (unicodeTypeL(word0->text[i])) { ++lrCount; } else if (unicodeTypeR(word0->text[i])) { --lrCount; } } } } } primaryLR = lrCount >= 0; #if 0 // for debugging printf("*** direction ***\n"); printf("lrCount = %d\n", lrCount); printf("primaryLR = %d\n", primaryLR); #endif //----- column assignment if (physLayout && fixedPitch) { blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); for (blk = blkList, i = 0; blk; blk = blk->next, ++i) { blocks[i] = blk; col1 = 0; // make gcc happy switch (primaryRot) { case 0: col1 = (int)(blk->xMin / fixedPitch + 0.5); break; case 1: col1 = (int)(blk->yMin / fixedPitch + 0.5); break; case 2: col1 = (int)((pageWidth - blk->xMax) / fixedPitch + 0.5); break; case 3: col1 = (int)((pageHeight - blk->yMax) / fixedPitch + 0.5); break; } blk->col = col1; for (line = blk->lines; line; line = line->next) { for (j = 0; j <= line->len; ++j) { line->col[j] += col1; } } } } else { // sort blocks into xy order for column assignment blocks = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); for (blk = blkList, i = 0; blk; blk = blk->next, ++i) { blocks[i] = blk; } qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot); // column assignment for (i = 0; i < nBlocks; ++i) { blk0 = blocks[i]; col1 = 0; for (j = 0; j < i; ++j) { blk1 = blocks[j]; col2 = 0; // make gcc happy switch (primaryRot) { case 0: if (blk0->xMin > blk1->xMax) { col2 = blk1->col + blk1->nColumns + 3; } else if (blk1->xMax == blk1->xMin) { col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) / (blk1->xMax - blk1->xMin)) * blk1->nColumns); } break; case 1: if (blk0->yMin > blk1->yMax) { col2 = blk1->col + blk1->nColumns + 3; } else if (blk1->yMax == blk1->yMin) { col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) / (blk1->yMax - blk1->yMin)) * blk1->nColumns); } break; case 2: if (blk0->xMax < blk1->xMin) { col2 = blk1->col + blk1->nColumns + 3; } else if (blk1->xMin == blk1->xMax) { col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) / (blk1->xMin - blk1->xMax)) * blk1->nColumns); } break; case 3: if (blk0->yMax < blk1->yMin) { col2 = blk1->col + blk1->nColumns + 3; } else if (blk1->yMin == blk1->yMax) { col2 = blk1->col; } else { col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) / (blk1->yMin - blk1->yMax)) * blk1->nColumns); } break; } if (col2 > col1) { col1 = col2; } } blk0->col = col1; for (line = blk0->lines; line; line = line->next) { for (j = 0; j <= line->len; ++j) { line->col[j] += col1; } } } } #if 0 // for debugging printf("*** blocks, after column assignment ***\n"); for (blk = blkList; blk; blk = blk->next) { printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n", blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col, blk->nColumns); for (line = blk->lines; line; line = line->next) { printf(" line: col[0]=%d\n", line->col[0]); for (word0 = line->words; word0; word0 = word0->next) { printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->base, word0->fontSize, word0->spaceAfter); for (i = 0; i < word0->len; ++i) { fputc(word0->text[i] & 0xff, stdout); } printf("'\n"); } } } printf("\n"); #endif //----- reading order sort // sort blocks into yx order (in preparation for reading order sort) qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpYXPrimaryRot); // compute space on left and right sides of each block for (i = 0; i < nBlocks; ++i) { blk0 = blocks[i]; for (j = 0; j < nBlocks; ++j) { blk1 = blocks[j]; if (blk1 != blk0) { blk0->updatePriMinMax(blk1); } } } #if 0 // for debugging printf("*** blocks, after yx sort ***\n"); for (i = 0; i < nBlocks; ++i) { blk = blocks[i]; printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n", blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->priMin, blk->priMax); for (line = blk->lines; line; line = line->next) { printf(" line:\n"); for (word0 = line->words; word0; word0 = word0->next) { printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->base, word0->fontSize, word0->spaceAfter); for (j = 0; j < word0->len; ++j) { fputc(word0->text[j] & 0xff, stdout); } printf("'\n"); } } } printf("\n"); #endif // build the flows //~ this needs to be adjusted for writing mode (vertical text) //~ this also needs to account for right-to-left column ordering blkArray = (TextBlock **)gmallocn(nBlocks, sizeof(TextBlock *)); memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *)); flows = lastFlow = NULL; firstBlkIdx = 0; nBlocksLeft = nBlocks; while (nBlocksLeft > 0) { // find the upper-left-most block for (; !blkArray[firstBlkIdx]; ++firstBlkIdx) ; i = firstBlkIdx; blk = blkArray[i]; for (j = firstBlkIdx + 1; j < nBlocks; ++j) { blk1 = blkArray[j]; if (blk1) { if (blk && blk->secondaryDelta(blk1) > 0) { break; } if (blk1->primaryCmp(blk) < 0) { i = j; blk = blk1; } } } blkArray[i] = NULL; --nBlocksLeft; blk->next = NULL; // create a new flow, starting with the upper-left-most block flow = new TextFlow(this, blk); if (lastFlow) { lastFlow->next = flow; } else { flows = flow; } lastFlow = flow; fontSize = blk->lines->words->fontSize; // push the upper-left-most block on the stack blk->stackNext = NULL; blkStack = blk; // find the other blocks in this flow while (blkStack) { // find the upper-left-most block under (but within // maxBlockSpacing of) the top block on the stack blkSpace = maxBlockSpacing * blkStack->lines->words->fontSize; blk = NULL; i = -1; for (j = firstBlkIdx; j < nBlocks; ++j) { blk1 = blkArray[j]; if (blk1) { if (blkStack->secondaryDelta(blk1) > blkSpace) { break; } if (blk && blk->secondaryDelta(blk1) > 0) { break; } if (blk1->isBelow(blkStack) && (!blk || blk1->primaryCmp(blk) < 0)) { i = j; blk = blk1; } } } // if a suitable block was found, add it to the flow and push it // onto the stack if (blk && flow->blockFits(blk, blkStack)) { blkArray[i] = NULL; --nBlocksLeft; blk->next = NULL; flow->addBlock(blk); fontSize = blk->lines->words->fontSize; blk->stackNext = blkStack; blkStack = blk; // otherwise (if there is no block under the top block or the // block is not suitable), pop the stack } else { blkStack = blkStack->stackNext; } } } gfree(blkArray); #if 0 // for debugging printf("*** flows ***\n"); for (flow = flows; flow; flow = flow->next) { printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n", flow->xMin, flow->xMax, flow->yMin, flow->yMax, flow->priMin, flow->priMax); for (blk = flow->blocks; blk; blk = blk->next) { printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n", blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->priMin, blk->priMax); for (line = blk->lines; line; line = line->next) { printf(" line:\n"); for (word0 = line->words; word0; word0 = word0->next) { printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '", word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->base, word0->fontSize, word0->spaceAfter); for (i = 0; i < word0->len; ++i) { fputc(word0->text[i] & 0xff, stdout); } printf("'\n"); } } } } printf("\n"); #endif if (uMap) { uMap->decRefCnt(); } } GBool TextPage::findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, GBool caseSensitive, GBool backward, GBool wholeWord, double *xMin, double *yMin, double *xMax, double *yMax) { TextBlock *blk; TextLine *line; Unicode *s2, *txt; Unicode *p; int txtSize, m, i, j, k; double xStart, yStart, xStop, yStop; double xMin0, yMin0, xMax0, yMax0; double xMin1, yMin1, xMax1, yMax1; GBool found; //~ needs to handle right-to-left text if (rawOrder) { return gFalse; } // convert the search string to uppercase if (!caseSensitive) { s2 = (Unicode *)gmallocn(len, sizeof(Unicode)); for (i = 0; i < len; ++i) { s2[i] = unicodeToUpper(s[i]); } } else { s2 = s; } txt = NULL; txtSize = 0; xStart = yStart = xStop = yStop = 0; if (startAtLast && haveLastFind) { xStart = lastFindXMin; yStart = lastFindYMin; } else if (!startAtTop) { xStart = *xMin; yStart = *yMin; } if (stopAtLast && haveLastFind) { xStop = lastFindXMin; yStop = lastFindYMin; } else if (!stopAtBottom) { xStop = *xMax; yStop = *yMax; } found = gFalse; xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy for (i = backward ? nBlocks - 1 : 0; backward ? i >= 0 : i < nBlocks; i += backward ? -1 : 1) { blk = blocks[i]; // check: is the block above the top limit? // (this only works if the page's primary rotation is zero -- // otherwise the blocks won't be sorted in the useful order) if (!startAtTop && primaryRot == 0 && (backward ? blk->yMin > yStart : blk->yMax < yStart)) { continue; } // check: is the block below the bottom limit? // (this only works if the page's primary rotation is zero -- // otherwise the blocks won't be sorted in the useful order) if (!stopAtBottom && primaryRot == 0 && (backward ? blk->yMax < yStop : blk->yMin > yStop)) { break; } for (line = blk->lines; line; line = line->next) { // check: is the line above the top limit? // (this only works if the page's primary rotation is zero -- // otherwise the lines won't be sorted in the useful order) if (!startAtTop && primaryRot == 0 && (backward ? line->yMin > yStart : line->yMin < yStart)) { continue; } // check: is the line below the bottom limit? // (this only works if the page's primary rotation is zero -- // otherwise the lines won't be sorted in the useful order) if (!stopAtBottom && primaryRot == 0 && (backward ? line->yMin < yStop : line->yMin > yStop)) { continue; } // convert the line to uppercase m = line->len; if (!caseSensitive) { if (m > txtSize) { txt = (Unicode *)greallocn(txt, m, sizeof(Unicode)); txtSize = m; } for (k = 0; k < m; ++k) { txt[k] = unicodeToUpper(line->text[k]); } } else { txt = line->text; } // search each position in this line j = backward ? m - len : 0; p = txt + j; while (backward ? j >= 0 : j <= m - len) { if (!wholeWord || ((j == 0 || !unicodeTypeAlphaNum(txt[j - 1])) && (j + len == m || !unicodeTypeAlphaNum(txt[j + len])))) { // compare the strings for (k = 0; k < len; ++k) { if (p[k] != s2[k]) { break; } } // found it if (k == len) { switch (line->rot) { case 0: xMin1 = line->edge[j]; xMax1 = line->edge[j + len]; yMin1 = line->yMin; yMax1 = line->yMax; break; case 1: xMin1 = line->xMin; xMax1 = line->xMax; yMin1 = line->edge[j]; yMax1 = line->edge[j + len]; break; case 2: xMin1 = line->edge[j + len]; xMax1 = line->edge[j]; yMin1 = line->yMin; yMax1 = line->yMax; break; case 3: xMin1 = line->xMin; xMax1 = line->xMax; yMin1 = line->edge[j + len]; yMax1 = line->edge[j]; break; } if (backward) { if ((startAtTop || yMin1 < yStart || (yMin1 == yStart && xMin1 < xStart)) && (stopAtBottom || yMin1 > yStop || (yMin1 == yStop && xMin1 > xStop))) { if (!found || yMin1 > yMin0 || (yMin1 == yMin0 && xMin1 > xMin0)) { xMin0 = xMin1; xMax0 = xMax1; yMin0 = yMin1; yMax0 = yMax1; found = gTrue; } } } else { if ((startAtTop || yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) && (stopAtBottom || yMin1 < yStop || (yMin1 == yStop && xMin1 < xStop))) { if (!found || yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) { xMin0 = xMin1; xMax0 = xMax1; yMin0 = yMin1; yMax0 = yMax1; found = gTrue; } } } } } if (backward) { --j; --p; } else { ++j; ++p; } } } } if (!caseSensitive) { gfree(s2); gfree(txt); } if (found) { *xMin = xMin0; *xMax = xMax0; *yMin = yMin0; *yMax = yMax0; lastFindXMin = xMin0; lastFindYMin = yMin0; haveLastFind = gTrue; return gTrue; } return gFalse; } GString *TextPage::getText(double xMin, double yMin, double xMax, double yMax) { GString *s; UnicodeMap *uMap; GBool isUnicode; TextBlock *blk; TextLine *line; TextLineFrag *frags; int nFrags, fragsSize; TextLineFrag *frag; char space[8], eol[16]; int spaceLen, eolLen; int lastRot; double x, y, delta; int col, idx0, idx1, i, j; GBool multiLine, oneRot; s = new GString(); if (rawOrder) { return s; } // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { return s; } isUnicode = uMap->isUnicode(); spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); eolLen = 0; // make gcc happy switch (globalParams->getTextEOL()) { case eolUnix: eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); break; case eolDOS: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); break; case eolMac: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); break; } //~ writing mode (horiz/vert) // collect the line fragments that are in the rectangle fragsSize = 256; frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); nFrags = 0; lastRot = -1; oneRot = gTrue; for (i = 0; i < nBlocks; ++i) { blk = blocks[i]; if (xMin < blk->xMax && blk->xMin < xMax && yMin < blk->yMax && blk->yMin < yMax) { for (line = blk->lines; line; line = line->next) { if (xMin < line->xMax && line->xMin < xMax && yMin < line->yMax && line->yMin < yMax) { idx0 = idx1 = -1; switch (line->rot) { case 0: y = 0.5 * (line->yMin + line->yMax); if (yMin < y && y < yMax) { j = 0; while (j < line->len) { if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { idx0 = j; break; } ++j; } j = line->len - 1; while (j >= 0) { if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { idx1 = j; break; } --j; } } break; case 1: x = 0.5 * (line->xMin + line->xMax); if (xMin < x && x < xMax) { j = 0; while (j < line->len) { if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { idx0 = j; break; } ++j; } j = line->len - 1; while (j >= 0) { if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { idx1 = j; break; } --j; } } break; case 2: y = 0.5 * (line->yMin + line->yMax); if (yMin < y && y < yMax) { j = 0; while (j < line->len) { if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) { idx0 = j; break; } ++j; } j = line->len - 1; while (j >= 0) { if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) { idx1 = j; break; } --j; } } break; case 3: x = 0.5 * (line->xMin + line->xMax); if (xMin < x && x < xMax) { j = 0; while (j < line->len) { if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) { idx0 = j; break; } ++j; } j = line->len - 1; while (j >= 0) { if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) { idx1 = j; break; } --j; } } break; } if (idx0 >= 0 && idx1 >= 0) { if (nFrags == fragsSize) { fragsSize *= 2; frags = (TextLineFrag *) greallocn(frags, fragsSize, sizeof(TextLineFrag)); } frags[nFrags].init(line, idx0, idx1 - idx0 + 1); ++nFrags; if (lastRot >= 0 && line->rot != lastRot) { oneRot = gFalse; } lastRot = line->rot; } } } } } // sort the fragments and generate the string if (nFrags > 0) { for (i = 0; i < nFrags; ++i) { frags[i].computeCoords(oneRot); } assignColumns(frags, nFrags, oneRot); // if all lines in the region have the same rotation, use it; // otherwise, use the page's primary rotation if (oneRot) { qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXLineRot); } else { qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot); } i = 0; while (i < nFrags) { delta = maxIntraLineDelta * frags[i].line->words->fontSize; for (j = i+1; j < nFrags && fabs(frags[j].base - frags[i].base) < delta; ++j) ; qsort(frags + i, j - i, sizeof(TextLineFrag), oneRot ? &TextLineFrag::cmpXYColumnLineRot : &TextLineFrag::cmpXYColumnPrimaryRot); i = j; } col = 0; multiLine = gFalse; for (i = 0; i < nFrags; ++i) { frag = &frags[i]; // insert a return if (frag->col < col || (i > 0 && fabs(frag->base - frags[i-1].base) > maxIntraLineDelta * frags[i-1].line->words->fontSize)) { s->append(eol, eolLen); col = 0; multiLine = gTrue; } // column alignment for (; col < frag->col; ++col) { s->append(space, spaceLen); } // get the fragment text col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); } if (multiLine) { s->append(eol, eolLen); } } gfree(frags); uMap->decRefCnt(); return s; } GBool TextPage::findCharRange(int pos, int length, double *xMin, double *yMin, double *xMax, double *yMax) { TextBlock *blk; TextLine *line; TextWord *word; double xMin0, xMax0, yMin0, yMax0; double xMin1, xMax1, yMin1, yMax1; GBool first; int i, j0, j1; if (rawOrder) { return gFalse; } //~ this doesn't correctly handle ranges split across multiple lines //~ (the highlighted region is the bounding box of all the parts of //~ the range) first = gTrue; xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy for (i = 0; i < nBlocks; ++i) { blk = blocks[i]; for (line = blk->lines; line; line = line->next) { for (word = line->words; word; word = word->next) { if (pos < word->charPos[word->len] && pos + length > word->charPos[0]) { for (j0 = 0; j0 < word->len && pos >= word->charPos[j0 + 1]; ++j0) ; for (j1 = word->len - 1; j1 > j0 && pos + length <= word->charPos[j1]; --j1) ; switch (line->rot) { case 0: xMin1 = word->edge[j0]; xMax1 = word->edge[j1 + 1]; yMin1 = word->yMin; yMax1 = word->yMax; break; case 1: xMin1 = word->xMin; xMax1 = word->xMax; yMin1 = word->edge[j0]; yMax1 = word->edge[j1 + 1]; break; case 2: xMin1 = word->edge[j1 + 1]; xMax1 = word->edge[j0]; yMin1 = word->yMin; yMax1 = word->yMax; break; case 3: xMin1 = word->xMin; xMax1 = word->xMax; yMin1 = word->edge[j1 + 1]; yMax1 = word->edge[j0]; break; } if (first || xMin1 < xMin0) { xMin0 = xMin1; } if (first || xMax1 > xMax0) { xMax0 = xMax1; } if (first || yMin1 < yMin0) { yMin0 = yMin1; } if (first || yMax1 > yMax0) { yMax0 = yMax1; } first = gFalse; } } } } if (!first) { *xMin = xMin0; *xMax = xMax0; *yMin = yMin0; *yMax = yMax0; return gTrue; } return gFalse; } void TextPage::dump(void *outputStream, TextOutputFunc outputFunc, GBool physLayout) { UnicodeMap *uMap; TextFlow *flow; TextBlock *blk; TextLine *line; TextLineFrag *frags; TextWord *word; int nFrags, fragsSize; TextLineFrag *frag; char space[8], eol[16], eop[8]; int spaceLen, eolLen, eopLen; GBool pageBreaks; GString *s; double delta; int col, i, j, d, n; // get the output encoding if (!(uMap = globalParams->getTextEncoding())) { return; } spaceLen = uMap->mapUnicode(0x20, space, sizeof(space)); eolLen = 0; // make gcc happy switch (globalParams->getTextEOL()) { case eolUnix: eolLen = uMap->mapUnicode(0x0a, eol, sizeof(eol)); break; case eolDOS: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); eolLen += uMap->mapUnicode(0x0a, eol + eolLen, sizeof(eol) - eolLen); break; case eolMac: eolLen = uMap->mapUnicode(0x0d, eol, sizeof(eol)); break; } eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop)); pageBreaks = globalParams->getTextPageBreaks(); //~ writing mode (horiz/vert) // output the page in raw (content stream) order if (rawOrder) { for (word = rawWords; word; word = word->next) { s = new GString(); dumpFragment(word->text, word->len, uMap, s); (*outputFunc)(outputStream, s->getCString(), s->getLength()); delete s; if (word->next && fabs(word->next->base - word->base) < maxIntraLineDelta * word->fontSize && word->next->xMin > word->xMax - minDupBreakOverlap * word->fontSize) { if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) { (*outputFunc)(outputStream, space, spaceLen); } } else { (*outputFunc)(outputStream, eol, eolLen); } } // output the page, maintaining the original physical layout } else if (physLayout) { // collect the line fragments for the page and sort them fragsSize = 256; frags = (TextLineFrag *)gmallocn(fragsSize, sizeof(TextLineFrag)); nFrags = 0; for (i = 0; i < nBlocks; ++i) { blk = blocks[i]; for (line = blk->lines; line; line = line->next) { if (nFrags == fragsSize) { fragsSize *= 2; frags = (TextLineFrag *)greallocn(frags, fragsSize, sizeof(TextLineFrag)); } frags[nFrags].init(line, 0, line->len); frags[nFrags].computeCoords(gTrue); ++nFrags; } } qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot); i = 0; while (i < nFrags) { delta = maxIntraLineDelta * frags[i].line->words->fontSize; for (j = i+1; j < nFrags && fabs(frags[j].base - frags[i].base) < delta; ++j) ; qsort(frags + i, j - i, sizeof(TextLineFrag), &TextLineFrag::cmpXYColumnPrimaryRot); i = j; } #if 0 // for debugging printf("*** line fragments ***\n"); for (i = 0; i < nFrags; ++i) { frag = &frags[i]; printf("frag: x=%.2f..%.2f y=%.2f..%.2f base=%.2f '", frag->xMin, frag->xMax, frag->yMin, frag->yMax, frag->base); for (n = 0; n < frag->len; ++n) { fputc(frag->line->text[frag->start + n] & 0xff, stdout); } printf("'\n"); } printf("\n"); #endif // generate output col = 0; for (i = 0; i < nFrags; ++i) { frag = &frags[i]; // column alignment for (; col < frag->col; ++col) { (*outputFunc)(outputStream, space, spaceLen); } // print the line s = new GString(); col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s); (*outputFunc)(outputStream, s->getCString(), s->getLength()); delete s; // print one or more returns if necessary if (i == nFrags - 1 || frags[i+1].col < col || fabs(frags[i+1].base - frag->base) > maxIntraLineDelta * frag->line->words->fontSize) { if (i < nFrags - 1) { d = (int)((frags[i+1].base - frag->base) / frag->line->words->fontSize); if (d < 1) { d = 1; } else if (d > 5) { d = 5; } } else { d = 1; } for (; d > 0; --d) { (*outputFunc)(outputStream, eol, eolLen); } col = 0; } } gfree(frags); // output the page, "undoing" the layout } else { for (flow = flows; flow; flow = flow->next) { for (blk = flow->blocks; blk; blk = blk->next) { for (line = blk->lines; line; line = line->next) { n = line->len; if (line->hyphenated && (line->next || blk->next)) { --n; } s = new GString(); dumpFragment(line->text, n, uMap, s); (*outputFunc)(outputStream, s->getCString(), s->getLength()); delete s; if (!line->hyphenated) { if (line->next) { (*outputFunc)(outputStream, space, spaceLen); } else if (blk->next) { //~ this is a bit of a kludge - we should really do a more //~ intelligent determination of paragraphs if (blk->next->lines->words->fontSize == blk->lines->words->fontSize) { (*outputFunc)(outputStream, space, spaceLen); } else { (*outputFunc)(outputStream, eol, eolLen); } } } } } (*outputFunc)(outputStream, eol, eolLen); (*outputFunc)(outputStream, eol, eolLen); } } // end of page if (pageBreaks) { (*outputFunc)(outputStream, eop, eopLen); } uMap->decRefCnt(); } void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) { TextLineFrag *frag0, *frag1; int rot, col1, col2, i, j, k; // all text in the region has the same rotation -- recompute the // column numbers based only on the text in the region if (oneRot) { qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot); rot = frags[0].line->rot; for (i = 0; i < nFrags; ++i) { frag0 = &frags[i]; col1 = 0; for (j = 0; j < i; ++j) { frag1 = &frags[j]; col2 = 0; // make gcc happy switch (rot) { case 0: if (frag0->xMin >= frag1->xMax) { col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start]) + 1; } else { for (k = frag1->start; k < frag1->start + frag1->len && frag0->xMin >= 0.5 * (frag1->line->edge[k] + frag1->line->edge[k+1]); ++k) ; col2 = frag1->col + frag1->line->col[k] - frag1->line->col[frag1->start]; } break; case 1: if (frag0->yMin >= frag1->yMax) { col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start]) + 1; } else { for (k = frag1->start; k < frag1->start + frag1->len && frag0->yMin >= 0.5 * (frag1->line->edge[k] + frag1->line->edge[k+1]); ++k) ; col2 = frag1->col + frag1->line->col[k] - frag1->line->col[frag1->start]; } break; case 2: if (frag0->xMax <= frag1->xMin) { col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start]) + 1; } else { for (k = frag1->start; k < frag1->start + frag1->len && frag0->xMax <= 0.5 * (frag1->line->edge[k] + frag1->line->edge[k+1]); ++k) ; col2 = frag1->col + frag1->line->col[k] - frag1->line->col[frag1->start]; } break; case 3: if (frag0->yMax <= frag1->yMin) { col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] - frag1->line->col[frag1->start]) + 1; } else { for (k = frag1->start; k < frag1->start + frag1->len && frag0->yMax <= 0.5 * (frag1->line->edge[k] + frag1->line->edge[k+1]); ++k) ; col2 = frag1->col + frag1->line->col[k] - frag1->line->col[frag1->start]; } break; } if (col2 > col1) { col1 = col2; } } frag0->col = col1; } // the region includes text at different rotations -- use the // globally assigned column numbers, offset by the minimum column // number (i.e., shift everything over to column 0) } else { col1 = frags[0].col; for (i = 1; i < nFrags; ++i) { if (frags[i].col < col1) { col1 = frags[i].col; } } for (i = 0; i < nFrags; ++i) { frags[i].col -= col1; } } } int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s) { char lre[8], rle[8], popdf[8], buf[8]; int lreLen, rleLen, popdfLen, n; int nCols, i, j, k; nCols = 0; if (uMap->isUnicode()) { lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre)); rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle)); popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf)); if (primaryLR) { i = 0; while (i < len) { // output a left-to-right section for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ; for (k = i; k < j; ++k) { n = uMap->mapUnicode(text[k], buf, sizeof(buf)); s->append(buf, n); ++nCols; } i = j; // output a right-to-left section for (j = i; j < len && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); ++j) ; if (j > i) { s->append(rle, rleLen); for (k = j - 1; k >= i; --k) { n = uMap->mapUnicode(text[k], buf, sizeof(buf)); s->append(buf, n); ++nCols; } s->append(popdf, popdfLen); i = j; } } } else { // Note: This code treats numeric characters (European and // Arabic/Indic) as left-to-right, which isn't strictly correct // (incurs extra LRE/POPDF pairs), but does produce correct // visual formatting. s->append(rle, rleLen); i = len - 1; while (i >= 0) { // output a right-to-left section for (j = i; j >= 0 && !(unicodeTypeL(text[j]) || unicodeTypeNum(text[j])); --j) ; for (k = i; k > j; --k) { n = uMap->mapUnicode(text[k], buf, sizeof(buf)); s->append(buf, n); ++nCols; } i = j; // output a left-to-right section for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ; if (j < i) { s->append(lre, lreLen); for (k = j + 1; k <= i; ++k) { n = uMap->mapUnicode(text[k], buf, sizeof(buf)); s->append(buf, n); ++nCols; } s->append(popdf, popdfLen); i = j; } } s->append(popdf, popdfLen); } } else { for (i = 0; i < len; ++i) { n = uMap->mapUnicode(text[i], buf, sizeof(buf)); s->append(buf, n); nCols += n; } } return nCols; } #if TEXTOUT_WORD_LIST TextWordList *TextPage::makeWordList(GBool physLayout) { return new TextWordList(this, physLayout); } #endif //------------------------------------------------------------------------ // TextOutputDev //------------------------------------------------------------------------ static void outputToFile(void *stream, const char *text, int len) { fwrite(text, 1, len, (FILE *)stream); } TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA, double fixedPitchA, GBool rawOrderA, GBool append) { text = NULL; physLayout = physLayoutA; fixedPitch = physLayout ? fixedPitchA : 0; rawOrder = rawOrderA; doHTML = gFalse; ok = gTrue; // open file needClose = gFalse; if (fileName) { if (!strcmp(fileName, "-")) { outputStream = stdout; #ifdef WIN32 // keep DOS from munging the end-of-line characters setmode(fileno(stdout), O_BINARY); #endif } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) { needClose = gTrue; } else { error(errIO, -1, "Couldn't open text file '{0:s}'", fileName); ok = gFalse; return; } outputFunc = &outputToFile; } else { outputStream = NULL; } // set up text object text = new TextPage(rawOrderA); } TextOutputDev::TextOutputDev(TextOutputFunc func, void *stream, GBool physLayoutA, double fixedPitchA, GBool rawOrderA) { outputFunc = func; outputStream = stream; needClose = gFalse; physLayout = physLayoutA; fixedPitch = physLayout ? fixedPitchA : 0; rawOrder = rawOrderA; doHTML = gFalse; text = new TextPage(rawOrderA); ok = gTrue; } TextOutputDev::~TextOutputDev() { if (needClose) { #ifdef MACOS ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); #endif fclose((FILE *)outputStream); } if (text) { delete text; } } void TextOutputDev::startPage(int pageNum, GfxState *state) { text->startPage(state); } void TextOutputDev::endPage() { text->endPage(); text->coalesce(physLayout, fixedPitch, doHTML); if (outputStream) { text->dump(outputStream, outputFunc, physLayout); } } void TextOutputDev::restoreState(GfxState *state) { text->updateFont(state); } void TextOutputDev::updateFont(GfxState *state) { text->updateFont(state); } void TextOutputDev::beginString(GfxState *state, GString *s) { } void TextOutputDev::endString(GfxState *state) { } void TextOutputDev::drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode c, int nBytes, Unicode *u, int uLen) { text->addChar(state, x - originX, y - originY, dx, dy, c, nBytes, u, uLen); } void TextOutputDev::incCharCount(int nChars) { text->incCharCount(nChars); } void TextOutputDev::beginActualText(GfxState *state, Unicode *u, int uLen) { text->beginActualText(state, u, uLen); } void TextOutputDev::endActualText(GfxState *state) { text->endActualText(state); } void TextOutputDev::stroke(GfxState *state) { GfxPath *path; GfxSubpath *subpath; double x[2], y[2]; if (!doHTML) { return; } path = state->getPath(); if (path->getNumSubpaths() != 1) { return; } subpath = path->getSubpath(0); if (subpath->getNumPoints() != 2) { return; } state->transform(subpath->getX(0), subpath->getY(0), &x[0], &y[0]); state->transform(subpath->getX(1), subpath->getY(1), &x[1], &y[1]); // look for a vertical or horizontal line if (x[0] == x[1] || y[0] == y[1]) { text->addUnderline(x[0], y[0], x[1], y[1]); } } void TextOutputDev::fill(GfxState *state) { GfxPath *path; GfxSubpath *subpath; double x[5], y[5]; double rx0, ry0, rx1, ry1, t; int i; if (!doHTML) { return; } path = state->getPath(); if (path->getNumSubpaths() != 1) { return; } subpath = path->getSubpath(0); if (subpath->getNumPoints() != 5) { return; } for (i = 0; i < 5; ++i) { if (subpath->getCurve(i)) { return; } state->transform(subpath->getX(i), subpath->getY(i), &x[i], &y[i]); } // look for a rectangle if (x[0] == x[1] && y[1] == y[2] && x[2] == x[3] && y[3] == y[4] && x[0] == x[4] && y[0] == y[4]) { rx0 = x[0]; ry0 = y[0]; rx1 = x[2]; ry1 = y[1]; } else if (y[0] == y[1] && x[1] == x[2] && y[2] == y[3] && x[3] == x[4] && x[0] == x[4] && y[0] == y[4]) { rx0 = x[0]; ry0 = y[0]; rx1 = x[1]; ry1 = y[2]; } else { return; } if (rx1 < rx0) { t = rx0; rx0 = rx1; rx1 = t; } if (ry1 < ry0) { t = ry0; ry0 = ry1; ry1 = t; } // skinny horizontal rectangle if (ry1 - ry0 < rx1 - rx0) { if (ry1 - ry0 < maxUnderlineWidth) { ry0 = 0.5 * (ry0 + ry1); text->addUnderline(rx0, ry0, rx1, ry0); } // skinny vertical rectangle } else { if (rx1 - rx0 < maxUnderlineWidth) { rx0 = 0.5 * (rx0 + rx1); text->addUnderline(rx0, ry0, rx0, ry1); } } } void TextOutputDev::eoFill(GfxState *state) { if (!doHTML) { return; } fill(state); } void TextOutputDev::processLink(Link *link) { double x1, y1, x2, y2; int xMin, yMin, xMax, yMax, x, y; if (!doHTML) { return; } link->getRect(&x1, &y1, &x2, &y2); cvtUserToDev(x1, y1, &x, &y); xMin = xMax = x; yMin = yMax = y; cvtUserToDev(x1, y2, &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } cvtUserToDev(x2, y1, &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } cvtUserToDev(x2, y2, &x, &y); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } text->addLink(xMin, yMin, xMax, yMax, link); } GBool TextOutputDev::findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, GBool caseSensitive, GBool backward, GBool wholeWord, double *xMin, double *yMin, double *xMax, double *yMax) { return text->findText(s, len, startAtTop, stopAtBottom, startAtLast, stopAtLast, caseSensitive, backward, wholeWord, xMin, yMin, xMax, yMax); } GString *TextOutputDev::getText(double xMin, double yMin, double xMax, double yMax) { return text->getText(xMin, yMin, xMax, yMax); } GBool TextOutputDev::findCharRange(int pos, int length, double *xMin, double *yMin, double *xMax, double *yMax) { return text->findCharRange(pos, length, xMin, yMin, xMax, yMax); } #if TEXTOUT_WORD_LIST TextWordList *TextOutputDev::makeWordList() { return text->makeWordList(physLayout); } #endif TextPage *TextOutputDev::takeText() { TextPage *ret; ret = text; text = new TextPage(rawOrder); return ret; } xpdf-3.03/xpdf/pdftops.cc0000644000076400007640000002266311622305345014653 0ustar dereknderekn//======================================================================== // // pdftops.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include #include #include #include "parseargs.h" #include "GString.h" #include "gmem.h" #include "GlobalParams.h" #include "Object.h" #include "Stream.h" #include "Array.h" #include "Dict.h" #include "XRef.h" #include "Catalog.h" #include "Page.h" #include "PDFDoc.h" #include "PSOutputDev.h" #include "Error.h" #include "config.h" static int firstPage = 1; static int lastPage = 0; static GBool level1 = gFalse; static GBool level1Sep = gFalse; static GBool level2 = gFalse; static GBool level2Sep = gFalse; static GBool level3 = gFalse; static GBool level3Sep = gFalse; static GBool doEPS = gFalse; static GBool doForm = gFalse; #if OPI_SUPPORT static GBool doOPI = gFalse; #endif static GBool noEmbedT1Fonts = gFalse; static GBool noEmbedTTFonts = gFalse; static GBool noEmbedCIDPSFonts = gFalse; static GBool noEmbedCIDTTFonts = gFalse; static GBool preload = gFalse; static char paperSize[15] = ""; static int paperWidth = 0; static int paperHeight = 0; static GBool noCrop = gFalse; static GBool expand = gFalse; static GBool noShrink = gFalse; static GBool noCenter = gFalse; static GBool pageCrop = gFalse; static GBool duplex = gFalse; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; static GBool quiet = gFalse; static char cfgFileName[256] = ""; static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { {"-f", argInt, &firstPage, 0, "first page to print"}, {"-l", argInt, &lastPage, 0, "last page to print"}, {"-level1", argFlag, &level1, 0, "generate Level 1 PostScript"}, {"-level1sep", argFlag, &level1Sep, 0, "generate Level 1 separable PostScript"}, {"-level2", argFlag, &level2, 0, "generate Level 2 PostScript"}, {"-level2sep", argFlag, &level2Sep, 0, "generate Level 2 separable PostScript"}, {"-level3", argFlag, &level3, 0, "generate Level 3 PostScript"}, {"-level3sep", argFlag, &level3Sep, 0, "generate Level 3 separable PostScript"}, {"-eps", argFlag, &doEPS, 0, "generate Encapsulated PostScript (EPS)"}, {"-form", argFlag, &doForm, 0, "generate a PostScript form"}, #if OPI_SUPPORT {"-opi", argFlag, &doOPI, 0, "generate OPI comments"}, #endif {"-noembt1", argFlag, &noEmbedT1Fonts, 0, "don't embed Type 1 fonts"}, {"-noembtt", argFlag, &noEmbedTTFonts, 0, "don't embed TrueType fonts"}, {"-noembcidps", argFlag, &noEmbedCIDPSFonts, 0, "don't embed CID PostScript fonts"}, {"-noembcidtt", argFlag, &noEmbedCIDTTFonts, 0, "don't embed CID TrueType fonts"}, {"-preload", argFlag, &preload, 0, "preload images and forms"}, {"-paper", argString, paperSize, sizeof(paperSize), "paper size (letter, legal, A4, A3, match)"}, {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, {"-paperh", argInt, &paperHeight, 0, "paper height, in points"}, {"-nocrop", argFlag, &noCrop, 0, "don't crop pages to CropBox"}, {"-expand", argFlag, &expand, 0, "expand pages smaller than the paper size"}, {"-noshrink", argFlag, &noShrink, 0, "don't shrink pages larger than the paper size"}, {"-nocenter", argFlag, &noCenter, 0, "don't center pages smaller than the paper size"}, {"-pagecrop", argFlag, &pageCrop, 0, "treat the CropBox as the page size"}, {"-duplex", argFlag, &duplex, 0, "enable duplex printing"}, {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, {"-h", argFlag, &printHelp, 0, "print usage information"}, {"-help", argFlag, &printHelp, 0, "print usage information"}, {"--help", argFlag, &printHelp, 0, "print usage information"}, {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; int main(int argc, char *argv[]) { PDFDoc *doc; GString *fileName; GString *psFileName; PSLevel level; PSOutMode mode; GString *ownerPW, *userPW; PSOutputDev *psOut; GBool ok; char *p; int exitCode; exitCode = 99; // parse args ok = parseArgs(argDesc, &argc, argv); if (!ok || argc < 2 || argc > 3 || printVersion || printHelp) { fprintf(stderr, "pdftops version %s\n", xpdfVersion); fprintf(stderr, "%s\n", xpdfCopyright); if (!printVersion) { printUsage("pdftops", " []", argDesc); } exit(1); } if ((level1 ? 1 : 0) + (level1Sep ? 1 : 0) + (level2 ? 1 : 0) + (level2Sep ? 1 : 0) + (level3 ? 1 : 0) + (level3Sep ? 1 : 0) > 1) { fprintf(stderr, "Error: use only one of the 'level' options.\n"); exit(1); } if (doEPS && doForm) { fprintf(stderr, "Error: use only one of -eps and -form\n"); exit(1); } if (level1) { level = psLevel1; } else if (level1Sep) { level = psLevel1Sep; } else if (level2Sep) { level = psLevel2Sep; } else if (level3) { level = psLevel3; } else if (level3Sep) { level = psLevel3Sep; } else { level = psLevel2; } if (doForm && level < psLevel2) { fprintf(stderr, "Error: forms are only available with Level 2 output.\n"); exit(1); } mode = doEPS ? psModeEPS : doForm ? psModeForm : psModePS; fileName = new GString(argv[1]); // read config file globalParams = new GlobalParams(cfgFileName); #if HAVE_SPLASH globalParams->setupBaseFonts(NULL); #endif if (paperSize[0]) { if (!globalParams->setPSPaperSize(paperSize)) { fprintf(stderr, "Invalid paper size\n"); delete fileName; goto err0; } } else { if (paperWidth) { globalParams->setPSPaperWidth(paperWidth); } if (paperHeight) { globalParams->setPSPaperHeight(paperHeight); } } if (noCrop) { globalParams->setPSCrop(gFalse); } if (expand) { globalParams->setPSExpandSmaller(gTrue); } if (noShrink) { globalParams->setPSShrinkLarger(gFalse); } if (noCenter) { globalParams->setPSCenter(gFalse); } if (duplex) { globalParams->setPSDuplex(duplex); } if (level1 || level1Sep || level2 || level2Sep || level3 || level3Sep) { globalParams->setPSLevel(level); } if (noEmbedT1Fonts) { globalParams->setPSEmbedType1(!noEmbedT1Fonts); } if (noEmbedTTFonts) { globalParams->setPSEmbedTrueType(!noEmbedTTFonts); } if (noEmbedCIDPSFonts) { globalParams->setPSEmbedCIDPostScript(!noEmbedCIDPSFonts); } if (noEmbedCIDTTFonts) { globalParams->setPSEmbedCIDTrueType(!noEmbedCIDTTFonts); } if (preload) { globalParams->setPSPreload(preload); } #if OPI_SUPPORT if (doOPI) { globalParams->setPSOPI(doOPI); } #endif if (quiet) { globalParams->setErrQuiet(quiet); } // open PDF file if (ownerPassword[0] != '\001') { ownerPW = new GString(ownerPassword); } else { ownerPW = NULL; } if (userPassword[0] != '\001') { userPW = new GString(userPassword); } else { userPW = NULL; } doc = new PDFDoc(fileName, ownerPW, userPW); if (userPW) { delete userPW; } if (ownerPW) { delete ownerPW; } if (!doc->isOk()) { exitCode = 1; goto err1; } // check for print permission if (!doc->okToPrint()) { error(errNotAllowed, -1, "Printing this document is not allowed."); exitCode = 3; goto err1; } // construct PostScript file name if (argc == 3) { psFileName = new GString(argv[2]); } else { p = fileName->getCString() + fileName->getLength() - 4; if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) { psFileName = new GString(fileName->getCString(), fileName->getLength() - 4); } else { psFileName = fileName->copy(); } psFileName->append(doEPS ? ".eps" : ".ps"); } // get page range if (firstPage < 1) { firstPage = 1; } if (lastPage < 1 || lastPage > doc->getNumPages()) { lastPage = doc->getNumPages(); } // check for multi-page EPS or form if ((doEPS || doForm) && firstPage != lastPage) { error(errCommandLine, -1, "EPS and form files can only contain one page."); goto err2; } // write PostScript file psOut = new PSOutputDev(psFileName->getCString(), doc, firstPage, lastPage, mode); if (psOut->isOk()) { doc->displayPages(psOut, firstPage, lastPage, 72, 72, 0, !pageCrop, globalParams->getPSCrop(), gTrue); } else { delete psOut; exitCode = 2; goto err2; } delete psOut; exitCode = 0; // clean up err2: delete psFileName; err1: delete doc; err0: delete globalParams; // check for memory leaks Object::memCheck(stderr); gMemReport(stderr); return exitCode; } xpdf-3.03/xpdf/BuiltinFont.cc0000644000076400007640000000251111622305345015417 0ustar dereknderekn//======================================================================== // // BuiltinFont.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "FontEncodingTables.h" #include "BuiltinFont.h" //------------------------------------------------------------------------ BuiltinFontWidths::BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA) { int i, h; size = sizeA; tab = (BuiltinFontWidth **)gmallocn(size, sizeof(BuiltinFontWidth *)); for (i = 0; i < size; ++i) { tab[i] = NULL; } for (i = 0; i < sizeA; ++i) { h = hash(widths[i].name); widths[i].next = tab[h]; tab[h] = &widths[i]; } } BuiltinFontWidths::~BuiltinFontWidths() { gfree(tab); } GBool BuiltinFontWidths::getWidth(const char *name, Gushort *width) { int h; BuiltinFontWidth *p; h = hash(name); for (p = tab[h]; p; p = p->next) { if (!strcmp(p->name, name)) { *width = p->width; return gTrue; } } return gFalse; } int BuiltinFontWidths::hash(const char *name) { const char *p; unsigned int h; h = 0; for (p = name; *p; ++p) { h = 17 * h + (int)(*p & 0xff); } return (int)(h % size); } xpdf-3.03/xpdf/CMap.h0000644000076400007640000000613311622305345013650 0ustar dereknderekn//======================================================================== // // CMap.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef CMAP_H #define CMAP_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "CharTypes.h" #if MULTITHREADED #include "GMutex.h" #endif class GString; class Object; class Stream; struct CMapVectorEntry; class CMapCache; //------------------------------------------------------------------------ class CMap { public: // Parse a CMap from , which can be a name or a stream. Sets // the initial reference count to 1. Returns NULL on failure. static CMap *parse(CMapCache *cache, GString *collectionA, Object *obj); // Create the CMap specified by and . Sets // the initial reference count to 1. Returns NULL on failure. static CMap *parse(CMapCache *cache, GString *collectionA, GString *cMapNameA); // Parse a CMap from . Sets the initial reference count to 1. // Returns NULL on failure. static CMap *parse(CMapCache *cache, GString *collectionA, Stream *str); ~CMap(); void incRefCnt(); void decRefCnt(); // Return collection name (-). GString *getCollection() { return collection; } // Return true if this CMap matches the specified , and // . GBool match(GString *collectionA, GString *cMapNameA); // Return the CID corresponding to the character code starting at // , which contains bytes. Sets * to the char code, and // * to the number of bytes used by the char code. CID getCID(char *s, int len, CharCode *c, int *nUsed); // Return the writing mode (0=horizontal, 1=vertical). int getWMode() { return wMode; } private: void parse2(CMapCache *cache, int (*getCharFunc)(void *), void *data); CMap(GString *collectionA, GString *cMapNameA); CMap(GString *collectionA, GString *cMapNameA, int wModeA); void useCMap(CMapCache *cache, char *useName); void useCMap(CMapCache *cache, Object *obj); void copyVector(CMapVectorEntry *dest, CMapVectorEntry *src); void addCIDs(Guint start, Guint end, Guint nBytes, CID firstCID); void freeCMapVector(CMapVectorEntry *vec); GString *collection; GString *cMapName; GBool isIdent; // true if this CMap is an identity mapping, // or is based on one (via usecmap) int wMode; // writing mode (0=horizontal, 1=vertical) CMapVectorEntry *vector; // vector for first byte (NULL for // identity CMap) int refCnt; #if MULTITHREADED GMutex mutex; #endif }; //------------------------------------------------------------------------ #define cMapCacheSize 4 class CMapCache { public: CMapCache(); ~CMapCache(); // Get the CMap for the specified character collection. // Increments its reference count; there will be one reference for // the cache plus one for the caller of this function. Returns NULL // on failure. CMap *getCMap(GString *collection, GString *cMapName); private: CMap *cache[cMapCacheSize]; }; #endif xpdf-3.03/xpdf/Gfx.h0000644000076400007640000002553411622305345013562 0ustar dereknderekn//======================================================================== // // Gfx.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFX_H #define GFX_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" class GString; class GList; class PDFDoc; class XRef; class Array; class Stream; class Parser; class Dict; class Function; class OutputDev; class GfxFontDict; class GfxFont; class GfxPattern; class GfxTilingPattern; class GfxShadingPattern; class GfxShading; class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; class GfxGouraudTriangleShading; class GfxPatchMeshShading; struct GfxPatch; class GfxState; struct GfxColor; class GfxColorSpace; class Gfx; class PDFRectangle; class AnnotBorderStyle; //------------------------------------------------------------------------ enum GfxClipType { clipNone, clipNormal, clipEO }; enum TchkType { tchkBool, // boolean tchkInt, // integer tchkNum, // number (integer or real) tchkString, // string tchkName, // name tchkArray, // array tchkProps, // properties (dictionary or name) tchkSCN, // scn/SCN args (number of name) tchkNone // used to avoid empty initializer lists }; #define maxArgs 33 struct Operator { char name[4]; int numArgs; TchkType tchk[maxArgs]; void (Gfx::*func)(Object args[], int numArgs); }; //------------------------------------------------------------------------ class GfxResources { public: GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA); ~GfxResources(); GfxFont *lookupFont(char *name); GBool lookupXObject(char *name, Object *obj); GBool lookupXObjectNF(char *name, Object *obj); void lookupColorSpace(char *name, Object *obj); GfxPattern *lookupPattern(char *name); GfxShading *lookupShading(char *name); GBool lookupGState(char *name, Object *obj); GBool lookupPropertiesNF(char *name, Object *obj); GfxResources *getNext() { return next; } private: GfxFontDict *fonts; Object xObjDict; Object colorSpaceDict; Object patternDict; Object shadingDict; Object gStateDict; Object propsDict; GfxResources *next; }; //------------------------------------------------------------------------ // GfxMarkedContent //------------------------------------------------------------------------ enum GfxMarkedContentKind { gfxMCOptionalContent, gfxMCActualText, gfxMCOther }; class GfxMarkedContent { public: GfxMarkedContent(GfxMarkedContentKind kindA, GBool ocStateA) { kind = kindA; ocState = ocStateA; } ~GfxMarkedContent() {} GfxMarkedContentKind kind; GBool ocState; // true if drawing is enabled, false if // disabled }; //------------------------------------------------------------------------ // Gfx //------------------------------------------------------------------------ class Gfx { public: // Constructor for regular output. Gfx(PDFDoc *docA, OutputDev *outA, int pageNum, Dict *resDict, double hDPI, double vDPI, PDFRectangle *box, PDFRectangle *cropBox, int rotate, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); // Constructor for a sub-page object. Gfx(PDFDoc *docA, OutputDev *outA, Dict *resDict, PDFRectangle *box, PDFRectangle *cropBox, GBool (*abortCheckCbkA)(void *data) = NULL, void *abortCheckCbkDataA = NULL); ~Gfx(); // Interpret a stream or array of streams. void display(Object *obj, GBool topLevel = gTrue); // Display an annotation, given its appearance (a Form XObject), // border style, and bounding box (in default user space). void drawAnnot(Object *str, AnnotBorderStyle *borderStyle, double xMin, double yMin, double xMax, double yMax); // Save graphics state. void saveState(); // Restore graphics state. void restoreState(); // Get the current graphics state object. GfxState *getState() { return state; } void drawForm(Object *str, Dict *resDict, double *matrix, double *bbox, GBool transpGroup = gFalse, GBool softMask = gFalse, GfxColorSpace *blendingColorSpace = NULL, GBool isolated = gFalse, GBool knockout = gFalse, GBool alpha = gFalse, Function *transferFunc = NULL, GfxColor *backdropColor = NULL); private: PDFDoc *doc; XRef *xref; // the xref table for this PDF file OutputDev *out; // output device GBool subPage; // is this a sub-page object? GBool printCommands; // print the drawing commands (for debugging) GfxResources *res; // resource stack int updateLevel; GfxState *state; // current graphics state GBool fontChanged; // set if font or text matrix has changed GfxClipType clip; // do a clip? int ignoreUndef; // current BX/EX nesting level double baseMatrix[6]; // default matrix for most recent // page/form/pattern int formDepth; double textClipBBox[4]; // text clipping bounding box GBool textClipBBoxEmpty; // true if textClipBBox has not been // initialized yet GBool ocState; // true if drawing is enabled, false if // disabled GList *markedContentStack; // BMC/BDC/EMC stack [GfxMarkedContent] Parser *parser; // parser for page content stream(s) GBool // callback to check for an abort (*abortCheckCbk)(void *data); void *abortCheckCbkData; static Operator opTab[]; // table of operators void go(GBool topLevel); void execOp(Object *cmd, Object args[], int numArgs); Operator *findOp(char *name); GBool checkArg(Object *arg, TchkType type); int getPos(); // graphics state operators void opSave(Object args[], int numArgs); void opRestore(Object args[], int numArgs); void opConcat(Object args[], int numArgs); void opSetDash(Object args[], int numArgs); void opSetFlat(Object args[], int numArgs); void opSetLineJoin(Object args[], int numArgs); void opSetLineCap(Object args[], int numArgs); void opSetMiterLimit(Object args[], int numArgs); void opSetLineWidth(Object args[], int numArgs); void opSetExtGState(Object args[], int numArgs); void doSoftMask(Object *str, GBool alpha, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, Function *transferFunc, GfxColor *backdropColor); void opSetRenderingIntent(Object args[], int numArgs); // color operators void opSetFillGray(Object args[], int numArgs); void opSetStrokeGray(Object args[], int numArgs); void opSetFillCMYKColor(Object args[], int numArgs); void opSetStrokeCMYKColor(Object args[], int numArgs); void opSetFillRGBColor(Object args[], int numArgs); void opSetStrokeRGBColor(Object args[], int numArgs); void opSetFillColorSpace(Object args[], int numArgs); void opSetStrokeColorSpace(Object args[], int numArgs); void opSetFillColor(Object args[], int numArgs); void opSetStrokeColor(Object args[], int numArgs); void opSetFillColorN(Object args[], int numArgs); void opSetStrokeColorN(Object args[], int numArgs); // path segment operators void opMoveTo(Object args[], int numArgs); void opLineTo(Object args[], int numArgs); void opCurveTo(Object args[], int numArgs); void opCurveTo1(Object args[], int numArgs); void opCurveTo2(Object args[], int numArgs); void opRectangle(Object args[], int numArgs); void opClosePath(Object args[], int numArgs); // path painting operators void opEndPath(Object args[], int numArgs); void opStroke(Object args[], int numArgs); void opCloseStroke(Object args[], int numArgs); void opFill(Object args[], int numArgs); void opEOFill(Object args[], int numArgs); void opFillStroke(Object args[], int numArgs); void opCloseFillStroke(Object args[], int numArgs); void opEOFillStroke(Object args[], int numArgs); void opCloseEOFillStroke(Object args[], int numArgs); void doPatternFill(GBool eoFill); void doPatternStroke(); void doPatternText(); void doPatternImageMask(Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); void doTilingPatternFill(GfxTilingPattern *tPat, GBool stroke, GBool eoFill, GBool text); void doShadingPatternFill(GfxShadingPattern *sPat, GBool stroke, GBool eoFill, GBool text); void opShFill(Object args[], int numArgs); void doFunctionShFill(GfxFunctionShading *shading); void doFunctionShFill1(GfxFunctionShading *shading, double x0, double y0, double x1, double y1, GfxColor *colors, int depth); void doAxialShFill(GfxAxialShading *shading); void doRadialShFill(GfxRadialShading *shading); void doGouraudTriangleShFill(GfxGouraudTriangleShading *shading); void gouraudFillTriangle(double x0, double y0, GfxColor *color0, double x1, double y1, GfxColor *color1, double x2, double y2, GfxColor *color2, int nComps, int depth); void doPatchMeshShFill(GfxPatchMeshShading *shading); void fillPatch(GfxPatch *patch, int nComps, int depth); void doEndPath(); // path clipping operators void opClip(Object args[], int numArgs); void opEOClip(Object args[], int numArgs); // text object operators void opBeginText(Object args[], int numArgs); void opEndText(Object args[], int numArgs); // text state operators void opSetCharSpacing(Object args[], int numArgs); void opSetFont(Object args[], int numArgs); void opSetTextLeading(Object args[], int numArgs); void opSetTextRender(Object args[], int numArgs); void opSetTextRise(Object args[], int numArgs); void opSetWordSpacing(Object args[], int numArgs); void opSetHorizScaling(Object args[], int numArgs); // text positioning operators void opTextMove(Object args[], int numArgs); void opTextMoveSet(Object args[], int numArgs); void opSetTextMatrix(Object args[], int numArgs); void opTextNextLine(Object args[], int numArgs); // text string operators void opShowText(Object args[], int numArgs); void opMoveShowText(Object args[], int numArgs); void opMoveSetShowText(Object args[], int numArgs); void opShowSpaceText(Object args[], int numArgs); void doShowText(GString *s); void doIncCharCount(GString *s); // XObject operators void opXObject(Object args[], int numArgs); void doImage(Object *ref, Stream *str, GBool inlineImg); void doForm(Object *str); // in-line image operators void opBeginImage(Object args[], int numArgs); Stream *buildImageStream(); void opImageData(Object args[], int numArgs); void opEndImage(Object args[], int numArgs); // type 3 font operators void opSetCharWidth(Object args[], int numArgs); void opSetCacheDevice(Object args[], int numArgs); // compatibility operators void opBeginIgnoreUndef(Object args[], int numArgs); void opEndIgnoreUndef(Object args[], int numArgs); // marked content operators void opBeginMarkedContent(Object args[], int numArgs); void opEndMarkedContent(Object args[], int numArgs); void opMarkPoint(Object args[], int numArgs); GfxState *saveStateStack(); void restoreStateStack(GfxState *oldState); void pushResources(Dict *resDict); void popResources(); }; #endif xpdf-3.03/xpdf/Parser.cc0000644000076400007640000001302211622305345014415 0ustar dereknderekn//======================================================================== // // Parser.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "Object.h" #include "Array.h" #include "Dict.h" #include "Decrypt.h" #include "Parser.h" #include "XRef.h" #include "Error.h" // Max number of nested objects. This is used to catch infinite loops // in the object structure. #define recursionLimit 500 Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) { xref = xrefA; lexer = lexerA; inlineImg = 0; allowStreams = allowStreamsA; lexer->getObj(&buf1); lexer->getObj(&buf2); } Parser::~Parser() { buf1.free(); buf2.free(); delete lexer; } Object *Parser::getObj(Object *obj, GBool simpleOnly, Guchar *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, int recursion) { char *key; Stream *str; Object obj2; int num; DecryptStream *decrypt; GString *s, *s2; int c; // refill buffer after inline image data if (inlineImg == 2) { buf1.free(); buf2.free(); lexer->getObj(&buf1); lexer->getObj(&buf2); inlineImg = 0; } // array if (!simpleOnly && recursion < recursionLimit && buf1.isCmd("[")) { shift(); obj->initArray(xref); while (!buf1.isCmd("]") && !buf1.isEOF()) obj->arrayAdd(getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1)); if (buf1.isEOF()) error(errSyntaxError, getPos(), "End of file inside array"); shift(); // dictionary or stream } else if (!simpleOnly && recursion < recursionLimit && buf1.isCmd("<<")) { shift(); obj->initDict(xref); while (!buf1.isCmd(">>") && !buf1.isEOF()) { if (!buf1.isName()) { error(errSyntaxError, getPos(), "Dictionary key must be a name object"); shift(); } else { key = copyString(buf1.getName()); shift(); if (buf1.isEOF() || buf1.isError()) { gfree(key); break; } obj->dictAdd(key, getObj(&obj2, gFalse, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1)); } } if (buf1.isEOF()) error(errSyntaxError, getPos(), "End of file inside dictionary"); // stream objects are not allowed inside content streams or // object streams if (allowStreams && buf2.isCmd("stream")) { if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength, objNum, objGen, recursion + 1))) { obj->initStream(str); } else { obj->free(); obj->initError(); } } else { shift(); } // indirect reference or integer } else if (buf1.isInt()) { num = buf1.getInt(); shift(); if (buf1.isInt() && buf2.isCmd("R")) { obj->initRef(num, buf1.getInt()); shift(); shift(); } else { obj->initInt(num); } // string } else if (buf1.isString() && fileKey) { s = buf1.getString(); s2 = new GString(); obj2.initNull(); decrypt = new DecryptStream(new MemStream(s->getCString(), 0, s->getLength(), &obj2), fileKey, encAlgorithm, keyLength, objNum, objGen); decrypt->reset(); while ((c = decrypt->getChar()) != EOF) { s2->append((char)c); } delete decrypt; obj->initString(s2); shift(); // simple object } else { buf1.copy(obj); shift(); } return obj; } Stream *Parser::makeStream(Object *dict, Guchar *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, int recursion) { Object obj; BaseStream *baseStr; Stream *str; Guint pos, endPos, length; // get stream start position lexer->skipToNextLine(); if (!(str = lexer->getStream())) { return NULL; } pos = str->getPos(); // get length dict->dictLookup("Length", &obj, recursion); if (obj.isInt()) { length = (Guint)obj.getInt(); obj.free(); } else { error(errSyntaxError, getPos(), "Bad 'Length' attribute in stream"); obj.free(); return NULL; } // check for length in damaged file if (xref && xref->getStreamEnd(pos, &endPos)) { length = endPos - pos; } // in badly damaged PDF files, we can run off the end of the input // stream immediately after the "stream" token if (!lexer->getStream()) { return NULL; } baseStr = lexer->getStream()->getBaseStream(); // skip over stream data lexer->setPos(pos + length); // refill token buffers and check for 'endstream' shift(); // kill '>>' shift(); // kill 'stream' if (buf1.isCmd("endstream")) { shift(); } else { error(errSyntaxError, getPos(), "Missing 'endstream'"); // kludge for broken PDF files: just add 5k to the length, and // hope its enough length += 5000; } // make base stream str = baseStr->makeSubStream(pos, gTrue, length, dict); // handle decryption if (fileKey) { str = new DecryptStream(str, fileKey, encAlgorithm, keyLength, objNum, objGen); } // get filters str = str->addFilters(dict); return str; } void Parser::shift() { if (inlineImg > 0) { if (inlineImg < 2) { ++inlineImg; } else { // in a damaged content stream, if 'ID' shows up in the middle // of a dictionary, we need to reset inlineImg = 0; } } else if (buf2.isCmd("ID")) { lexer->skipChar(); // skip char after 'ID' command inlineImg = 1; } buf1.free(); buf1 = buf2; if (inlineImg > 0) // don't buffer inline image data buf2.initNull(); else lexer->getObj(&buf2); } xpdf-3.03/xpdf/NameToUnicodeTable.h0000644000076400007640000034445511622305345016506 0ustar dereknderekn//======================================================================== // // NameToUnicodeTable.h // // Copyright 2001-2004 Glyph & Cog, LLC // //======================================================================== static struct { Unicode u; const char *name; } nameToUnicodeTab[] = { {0x0021, "!"}, {0x0023, "#"}, {0x0024, "$"}, {0x0025, "%"}, {0x0026, "&"}, {0x0027, "'"}, {0x0028, "("}, {0x0029, ")"}, {0x002a, "*"}, {0x002b, "+"}, {0x002c, ","}, {0x002d, "-"}, {0x002e, "."}, {0x002f, "/"}, {0x0030, "0"}, {0x0031, "1"}, {0x0032, "2"}, {0x0033, "3"}, {0x0034, "4"}, {0x0035, "5"}, {0x0036, "6"}, {0x0037, "7"}, {0x0038, "8"}, {0x0039, "9"}, {0x003a, ":"}, {0x003b, ";"}, {0x003c, "<"}, {0x003d, "="}, {0x003e, ">"}, {0x003f, "?"}, {0x0040, "@"}, {0x0041, "A"}, {0x00c6, "AE"}, {0x01fc, "AEacute"}, {0x01e2, "AEmacron"}, {0xf7e6, "AEsmall"}, {0x00c1, "Aacute"}, {0xf7e1, "Aacutesmall"}, {0x0102, "Abreve"}, {0x1eae, "Abreveacute"}, {0x04d0, "Abrevecyrillic"}, {0x1eb6, "Abrevedotbelow"}, {0x1eb0, "Abrevegrave"}, {0x1eb2, "Abrevehookabove"}, {0x1eb4, "Abrevetilde"}, {0x01cd, "Acaron"}, {0x24b6, "Acircle"}, {0x00c2, "Acircumflex"}, {0x1ea4, "Acircumflexacute"}, {0x1eac, "Acircumflexdotbelow"}, {0x1ea6, "Acircumflexgrave"}, {0x1ea8, "Acircumflexhookabove"}, {0xf7e2, "Acircumflexsmall"}, {0x1eaa, "Acircumflextilde"}, {0xf6c9, "Acute"}, {0xf7b4, "Acutesmall"}, {0x0410, "Acyrillic"}, {0x0200, "Adblgrave"}, {0x00c4, "Adieresis"}, {0x04d2, "Adieresiscyrillic"}, {0x01de, "Adieresismacron"}, {0xf7e4, "Adieresissmall"}, {0x1ea0, "Adotbelow"}, {0x01e0, "Adotmacron"}, {0x00c0, "Agrave"}, {0xf7e0, "Agravesmall"}, {0x1ea2, "Ahookabove"}, {0x04d4, "Aiecyrillic"}, {0x0202, "Ainvertedbreve"}, {0x0391, "Alpha"}, {0x0386, "Alphatonos"}, {0x0100, "Amacron"}, {0xff21, "Amonospace"}, {0x0104, "Aogonek"}, {0x00c5, "Aring"}, {0x01fa, "Aringacute"}, {0x1e00, "Aringbelow"}, {0xf7e5, "Aringsmall"}, {0xf761, "Asmall"}, {0x00c3, "Atilde"}, {0xf7e3, "Atildesmall"}, {0x0531, "Aybarmenian"}, {0x0042, "B"}, {0x24b7, "Bcircle"}, {0x1e02, "Bdotaccent"}, {0x1e04, "Bdotbelow"}, {0x0411, "Becyrillic"}, {0x0532, "Benarmenian"}, {0x0392, "Beta"}, {0x0181, "Bhook"}, {0x1e06, "Blinebelow"}, {0xff22, "Bmonospace"}, {0xf6f4, "Brevesmall"}, {0xf762, "Bsmall"}, {0x0182, "Btopbar"}, {0x0043, "C"}, {0x053e, "Caarmenian"}, {0x0106, "Cacute"}, {0xf6ca, "Caron"}, {0xf6f5, "Caronsmall"}, {0x010c, "Ccaron"}, {0x00c7, "Ccedilla"}, {0x1e08, "Ccedillaacute"}, {0xf7e7, "Ccedillasmall"}, {0x24b8, "Ccircle"}, {0x0108, "Ccircumflex"}, {0x010a, "Cdot"}, {0x010a, "Cdotaccent"}, {0xf7b8, "Cedillasmall"}, {0x0549, "Chaarmenian"}, {0x04bc, "Cheabkhasiancyrillic"}, {0x0427, "Checyrillic"}, {0x04be, "Chedescenderabkhasiancyrillic"}, {0x04b6, "Chedescendercyrillic"}, {0x04f4, "Chedieresiscyrillic"}, {0x0543, "Cheharmenian"}, {0x04cb, "Chekhakassiancyrillic"}, {0x04b8, "Cheverticalstrokecyrillic"}, {0x03a7, "Chi"}, {0x0187, "Chook"}, {0xf6f6, "Circumflexsmall"}, {0xff23, "Cmonospace"}, {0x0551, "Coarmenian"}, {0xf763, "Csmall"}, {0x0044, "D"}, {0x01f1, "DZ"}, {0x01c4, "DZcaron"}, {0x0534, "Daarmenian"}, {0x0189, "Dafrican"}, {0x010e, "Dcaron"}, {0x1e10, "Dcedilla"}, {0x24b9, "Dcircle"}, {0x1e12, "Dcircumflexbelow"}, {0x0110, "Dcroat"}, {0x1e0a, "Ddotaccent"}, {0x1e0c, "Ddotbelow"}, {0x0414, "Decyrillic"}, {0x03ee, "Deicoptic"}, {0x2206, "Delta"}, {0x0394, "Deltagreek"}, {0x018a, "Dhook"}, {0xf6cb, "Dieresis"}, {0xf6cc, "DieresisAcute"}, {0xf6cd, "DieresisGrave"}, {0xf7a8, "Dieresissmall"}, {0x03dc, "Digammagreek"}, {0x0402, "Djecyrillic"}, {0x1e0e, "Dlinebelow"}, {0xff24, "Dmonospace"}, {0xf6f7, "Dotaccentsmall"}, {0x0110, "Dslash"}, {0xf764, "Dsmall"}, {0x018b, "Dtopbar"}, {0x01f2, "Dz"}, {0x01c5, "Dzcaron"}, {0x04e0, "Dzeabkhasiancyrillic"}, {0x0405, "Dzecyrillic"}, {0x040f, "Dzhecyrillic"}, {0x0045, "E"}, {0x00c9, "Eacute"}, {0xf7e9, "Eacutesmall"}, {0x0114, "Ebreve"}, {0x011a, "Ecaron"}, {0x1e1c, "Ecedillabreve"}, {0x0535, "Echarmenian"}, {0x24ba, "Ecircle"}, {0x00ca, "Ecircumflex"}, {0x1ebe, "Ecircumflexacute"}, {0x1e18, "Ecircumflexbelow"}, {0x1ec6, "Ecircumflexdotbelow"}, {0x1ec0, "Ecircumflexgrave"}, {0x1ec2, "Ecircumflexhookabove"}, {0xf7ea, "Ecircumflexsmall"}, {0x1ec4, "Ecircumflextilde"}, {0x0404, "Ecyrillic"}, {0x0204, "Edblgrave"}, {0x00cb, "Edieresis"}, {0xf7eb, "Edieresissmall"}, {0x0116, "Edot"}, {0x0116, "Edotaccent"}, {0x1eb8, "Edotbelow"}, {0x0424, "Efcyrillic"}, {0x00c8, "Egrave"}, {0xf7e8, "Egravesmall"}, {0x0537, "Eharmenian"}, {0x1eba, "Ehookabove"}, {0x2167, "Eightroman"}, {0x0206, "Einvertedbreve"}, {0x0464, "Eiotifiedcyrillic"}, {0x041b, "Elcyrillic"}, {0x216a, "Elevenroman"}, {0x0112, "Emacron"}, {0x1e16, "Emacronacute"}, {0x1e14, "Emacrongrave"}, {0x041c, "Emcyrillic"}, {0xff25, "Emonospace"}, {0x041d, "Encyrillic"}, {0x04a2, "Endescendercyrillic"}, {0x014a, "Eng"}, {0x04a4, "Enghecyrillic"}, {0x04c7, "Enhookcyrillic"}, {0x0118, "Eogonek"}, {0x0190, "Eopen"}, {0x0395, "Epsilon"}, {0x0388, "Epsilontonos"}, {0x0420, "Ercyrillic"}, {0x018e, "Ereversed"}, {0x042d, "Ereversedcyrillic"}, {0x0421, "Escyrillic"}, {0x04aa, "Esdescendercyrillic"}, {0x01a9, "Esh"}, {0xf765, "Esmall"}, {0x0397, "Eta"}, {0x0538, "Etarmenian"}, {0x0389, "Etatonos"}, {0x00d0, "Eth"}, {0xf7f0, "Ethsmall"}, {0x1ebc, "Etilde"}, {0x1e1a, "Etildebelow"}, {0x20ac, "Euro"}, {0x01b7, "Ezh"}, {0x01ee, "Ezhcaron"}, {0x01b8, "Ezhreversed"}, {0x0046, "F"}, {0x24bb, "Fcircle"}, {0x1e1e, "Fdotaccent"}, {0x0556, "Feharmenian"}, {0x03e4, "Feicoptic"}, {0x0191, "Fhook"}, {0x0472, "Fitacyrillic"}, {0x2164, "Fiveroman"}, {0xff26, "Fmonospace"}, {0x2163, "Fourroman"}, {0xf766, "Fsmall"}, {0x0047, "G"}, {0x3387, "GBsquare"}, {0x01f4, "Gacute"}, {0x0393, "Gamma"}, {0x0194, "Gammaafrican"}, {0x03ea, "Gangiacoptic"}, {0x011e, "Gbreve"}, {0x01e6, "Gcaron"}, {0x0122, "Gcedilla"}, {0x24bc, "Gcircle"}, {0x011c, "Gcircumflex"}, {0x0122, "Gcommaaccent"}, {0x0120, "Gdot"}, {0x0120, "Gdotaccent"}, {0x0413, "Gecyrillic"}, {0x0542, "Ghadarmenian"}, {0x0494, "Ghemiddlehookcyrillic"}, {0x0492, "Ghestrokecyrillic"}, {0x0490, "Gheupturncyrillic"}, {0x0193, "Ghook"}, {0x0533, "Gimarmenian"}, {0x0403, "Gjecyrillic"}, {0x1e20, "Gmacron"}, {0xff27, "Gmonospace"}, {0xf6ce, "Grave"}, {0xf760, "Gravesmall"}, {0xf767, "Gsmall"}, {0x029b, "Gsmallhook"}, {0x01e4, "Gstroke"}, {0x0048, "H"}, {0x25cf, "H18533"}, {0x25aa, "H18543"}, {0x25ab, "H18551"}, {0x25a1, "H22073"}, {0x33cb, "HPsquare"}, {0x04a8, "Haabkhasiancyrillic"}, {0x04b2, "Hadescendercyrillic"}, {0x042a, "Hardsigncyrillic"}, {0x0126, "Hbar"}, {0x1e2a, "Hbrevebelow"}, {0x1e28, "Hcedilla"}, {0x24bd, "Hcircle"}, {0x0124, "Hcircumflex"}, {0x1e26, "Hdieresis"}, {0x1e22, "Hdotaccent"}, {0x1e24, "Hdotbelow"}, {0xff28, "Hmonospace"}, {0x0540, "Hoarmenian"}, {0x03e8, "Horicoptic"}, {0xf768, "Hsmall"}, {0xf6cf, "Hungarumlaut"}, {0xf6f8, "Hungarumlautsmall"}, {0x3390, "Hzsquare"}, {0x0049, "I"}, {0x042f, "IAcyrillic"}, {0x0132, "IJ"}, {0x042e, "IUcyrillic"}, {0x00cd, "Iacute"}, {0xf7ed, "Iacutesmall"}, {0x012c, "Ibreve"}, {0x01cf, "Icaron"}, {0x24be, "Icircle"}, {0x00ce, "Icircumflex"}, {0xf7ee, "Icircumflexsmall"}, {0x0406, "Icyrillic"}, {0x0208, "Idblgrave"}, {0x00cf, "Idieresis"}, {0x1e2e, "Idieresisacute"}, {0x04e4, "Idieresiscyrillic"}, {0xf7ef, "Idieresissmall"}, {0x0130, "Idot"}, {0x0130, "Idotaccent"}, {0x1eca, "Idotbelow"}, {0x04d6, "Iebrevecyrillic"}, {0x0415, "Iecyrillic"}, {0x2111, "Ifraktur"}, {0x00cc, "Igrave"}, {0xf7ec, "Igravesmall"}, {0x1ec8, "Ihookabove"}, {0x0418, "Iicyrillic"}, {0x020a, "Iinvertedbreve"}, {0x0419, "Iishortcyrillic"}, {0x012a, "Imacron"}, {0x04e2, "Imacroncyrillic"}, {0xff29, "Imonospace"}, {0x053b, "Iniarmenian"}, {0x0401, "Iocyrillic"}, {0x012e, "Iogonek"}, {0x0399, "Iota"}, {0x0196, "Iotaafrican"}, {0x03aa, "Iotadieresis"}, {0x038a, "Iotatonos"}, {0xf769, "Ismall"}, {0x0197, "Istroke"}, {0x0128, "Itilde"}, {0x1e2c, "Itildebelow"}, {0x0474, "Izhitsacyrillic"}, {0x0476, "Izhitsadblgravecyrillic"}, {0x004a, "J"}, {0x0541, "Jaarmenian"}, {0x24bf, "Jcircle"}, {0x0134, "Jcircumflex"}, {0x0408, "Jecyrillic"}, {0x054b, "Jheharmenian"}, {0xff2a, "Jmonospace"}, {0xf76a, "Jsmall"}, {0x004b, "K"}, {0x3385, "KBsquare"}, {0x33cd, "KKsquare"}, {0x04a0, "Kabashkircyrillic"}, {0x1e30, "Kacute"}, {0x041a, "Kacyrillic"}, {0x049a, "Kadescendercyrillic"}, {0x04c3, "Kahookcyrillic"}, {0x039a, "Kappa"}, {0x049e, "Kastrokecyrillic"}, {0x049c, "Kaverticalstrokecyrillic"}, {0x01e8, "Kcaron"}, {0x0136, "Kcedilla"}, {0x24c0, "Kcircle"}, {0x0136, "Kcommaaccent"}, {0x1e32, "Kdotbelow"}, {0x0554, "Keharmenian"}, {0x053f, "Kenarmenian"}, {0x0425, "Khacyrillic"}, {0x03e6, "Kheicoptic"}, {0x0198, "Khook"}, {0x040c, "Kjecyrillic"}, {0x1e34, "Klinebelow"}, {0xff2b, "Kmonospace"}, {0x0480, "Koppacyrillic"}, {0x03de, "Koppagreek"}, {0x046e, "Ksicyrillic"}, {0xf76b, "Ksmall"}, {0x004c, "L"}, {0x01c7, "LJ"}, {0xf6bf, "LL"}, {0x0139, "Lacute"}, {0x039b, "Lambda"}, {0x013d, "Lcaron"}, {0x013b, "Lcedilla"}, {0x24c1, "Lcircle"}, {0x1e3c, "Lcircumflexbelow"}, {0x013b, "Lcommaaccent"}, {0x013f, "Ldot"}, {0x013f, "Ldotaccent"}, {0x1e36, "Ldotbelow"}, {0x1e38, "Ldotbelowmacron"}, {0x053c, "Liwnarmenian"}, {0x01c8, "Lj"}, {0x0409, "Ljecyrillic"}, {0x1e3a, "Llinebelow"}, {0xff2c, "Lmonospace"}, {0x0141, "Lslash"}, {0xf6f9, "Lslashsmall"}, {0xf76c, "Lsmall"}, {0x004d, "M"}, {0x3386, "MBsquare"}, {0xf6d0, "Macron"}, {0xf7af, "Macronsmall"}, {0x1e3e, "Macute"}, {0x24c2, "Mcircle"}, {0x1e40, "Mdotaccent"}, {0x1e42, "Mdotbelow"}, {0x0544, "Menarmenian"}, {0xff2d, "Mmonospace"}, {0xf76d, "Msmall"}, {0x019c, "Mturned"}, {0x039c, "Mu"}, {0x004e, "N"}, {0x01ca, "NJ"}, {0x0143, "Nacute"}, {0x0147, "Ncaron"}, {0x0145, "Ncedilla"}, {0x24c3, "Ncircle"}, {0x1e4a, "Ncircumflexbelow"}, {0x0145, "Ncommaaccent"}, {0x1e44, "Ndotaccent"}, {0x1e46, "Ndotbelow"}, {0x019d, "Nhookleft"}, {0x2168, "Nineroman"}, {0x01cb, "Nj"}, {0x040a, "Njecyrillic"}, {0x1e48, "Nlinebelow"}, {0xff2e, "Nmonospace"}, {0x0546, "Nowarmenian"}, {0xf76e, "Nsmall"}, {0x00d1, "Ntilde"}, {0xf7f1, "Ntildesmall"}, {0x039d, "Nu"}, {0x004f, "O"}, {0x0152, "OE"}, {0xf6fa, "OEsmall"}, {0x00d3, "Oacute"}, {0xf7f3, "Oacutesmall"}, {0x04e8, "Obarredcyrillic"}, {0x04ea, "Obarreddieresiscyrillic"}, {0x014e, "Obreve"}, {0x01d1, "Ocaron"}, {0x019f, "Ocenteredtilde"}, {0x24c4, "Ocircle"}, {0x00d4, "Ocircumflex"}, {0x1ed0, "Ocircumflexacute"}, {0x1ed8, "Ocircumflexdotbelow"}, {0x1ed2, "Ocircumflexgrave"}, {0x1ed4, "Ocircumflexhookabove"}, {0xf7f4, "Ocircumflexsmall"}, {0x1ed6, "Ocircumflextilde"}, {0x041e, "Ocyrillic"}, {0x0150, "Odblacute"}, {0x020c, "Odblgrave"}, {0x00d6, "Odieresis"}, {0x04e6, "Odieresiscyrillic"}, {0xf7f6, "Odieresissmall"}, {0x1ecc, "Odotbelow"}, {0xf6fb, "Ogoneksmall"}, {0x00d2, "Ograve"}, {0xf7f2, "Ogravesmall"}, {0x0555, "Oharmenian"}, {0x2126, "Ohm"}, {0x1ece, "Ohookabove"}, {0x01a0, "Ohorn"}, {0x1eda, "Ohornacute"}, {0x1ee2, "Ohorndotbelow"}, {0x1edc, "Ohorngrave"}, {0x1ede, "Ohornhookabove"}, {0x1ee0, "Ohorntilde"}, {0x0150, "Ohungarumlaut"}, {0x01a2, "Oi"}, {0x020e, "Oinvertedbreve"}, {0x014c, "Omacron"}, {0x1e52, "Omacronacute"}, {0x1e50, "Omacrongrave"}, {0x2126, "Omega"}, {0x0460, "Omegacyrillic"}, {0x03a9, "Omegagreek"}, {0x047a, "Omegaroundcyrillic"}, {0x047c, "Omegatitlocyrillic"}, {0x038f, "Omegatonos"}, {0x039f, "Omicron"}, {0x038c, "Omicrontonos"}, {0xff2f, "Omonospace"}, {0x2160, "Oneroman"}, {0x01ea, "Oogonek"}, {0x01ec, "Oogonekmacron"}, {0x0186, "Oopen"}, {0x00d8, "Oslash"}, {0x01fe, "Oslashacute"}, {0xf7f8, "Oslashsmall"}, {0xf76f, "Osmall"}, {0x01fe, "Ostrokeacute"}, {0x047e, "Otcyrillic"}, {0x00d5, "Otilde"}, {0x1e4c, "Otildeacute"}, {0x1e4e, "Otildedieresis"}, {0xf7f5, "Otildesmall"}, {0x0050, "P"}, {0x1e54, "Pacute"}, {0x24c5, "Pcircle"}, {0x1e56, "Pdotaccent"}, {0x041f, "Pecyrillic"}, {0x054a, "Peharmenian"}, {0x04a6, "Pemiddlehookcyrillic"}, {0x03a6, "Phi"}, {0x01a4, "Phook"}, {0x03a0, "Pi"}, {0x0553, "Piwrarmenian"}, {0xff30, "Pmonospace"}, {0x03a8, "Psi"}, {0x0470, "Psicyrillic"}, {0xf770, "Psmall"}, {0x0051, "Q"}, {0x24c6, "Qcircle"}, {0xff31, "Qmonospace"}, {0xf771, "Qsmall"}, {0x0052, "R"}, {0x054c, "Raarmenian"}, {0x0154, "Racute"}, {0x0158, "Rcaron"}, {0x0156, "Rcedilla"}, {0x24c7, "Rcircle"}, {0x0156, "Rcommaaccent"}, {0x0210, "Rdblgrave"}, {0x1e58, "Rdotaccent"}, {0x1e5a, "Rdotbelow"}, {0x1e5c, "Rdotbelowmacron"}, {0x0550, "Reharmenian"}, {0x211c, "Rfraktur"}, {0x03a1, "Rho"}, {0xf6fc, "Ringsmall"}, {0x0212, "Rinvertedbreve"}, {0x1e5e, "Rlinebelow"}, {0xff32, "Rmonospace"}, {0xf772, "Rsmall"}, {0x0281, "Rsmallinverted"}, {0x02b6, "Rsmallinvertedsuperior"}, {0x0053, "S"}, {0x250c, "SF010000"}, {0x2514, "SF020000"}, {0x2510, "SF030000"}, {0x2518, "SF040000"}, {0x253c, "SF050000"}, {0x252c, "SF060000"}, {0x2534, "SF070000"}, {0x251c, "SF080000"}, {0x2524, "SF090000"}, {0x2500, "SF100000"}, {0x2502, "SF110000"}, {0x2561, "SF190000"}, {0x2562, "SF200000"}, {0x2556, "SF210000"}, {0x2555, "SF220000"}, {0x2563, "SF230000"}, {0x2551, "SF240000"}, {0x2557, "SF250000"}, {0x255d, "SF260000"}, {0x255c, "SF270000"}, {0x255b, "SF280000"}, {0x255e, "SF360000"}, {0x255f, "SF370000"}, {0x255a, "SF380000"}, {0x2554, "SF390000"}, {0x2569, "SF400000"}, {0x2566, "SF410000"}, {0x2560, "SF420000"}, {0x2550, "SF430000"}, {0x256c, "SF440000"}, {0x2567, "SF450000"}, {0x2568, "SF460000"}, {0x2564, "SF470000"}, {0x2565, "SF480000"}, {0x2559, "SF490000"}, {0x2558, "SF500000"}, {0x2552, "SF510000"}, {0x2553, "SF520000"}, {0x256b, "SF530000"}, {0x256a, "SF540000"}, {0x015a, "Sacute"}, {0x1e64, "Sacutedotaccent"}, {0x03e0, "Sampigreek"}, {0x0160, "Scaron"}, {0x1e66, "Scarondotaccent"}, {0xf6fd, "Scaronsmall"}, {0x015e, "Scedilla"}, {0x018f, "Schwa"}, {0x04d8, "Schwacyrillic"}, {0x04da, "Schwadieresiscyrillic"}, {0x24c8, "Scircle"}, {0x015c, "Scircumflex"}, {0x0218, "Scommaaccent"}, {0x1e60, "Sdotaccent"}, {0x1e62, "Sdotbelow"}, {0x1e68, "Sdotbelowdotaccent"}, {0x054d, "Seharmenian"}, {0x2166, "Sevenroman"}, {0x0547, "Shaarmenian"}, {0x0428, "Shacyrillic"}, {0x0429, "Shchacyrillic"}, {0x03e2, "Sheicoptic"}, {0x04ba, "Shhacyrillic"}, {0x03ec, "Shimacoptic"}, {0x03a3, "Sigma"}, {0x2165, "Sixroman"}, {0xff33, "Smonospace"}, {0x042c, "Softsigncyrillic"}, {0xf773, "Ssmall"}, {0x03da, "Stigmagreek"}, {0x0054, "T"}, {0x03a4, "Tau"}, {0x0166, "Tbar"}, {0x0164, "Tcaron"}, {0x0162, "Tcedilla"}, {0x24c9, "Tcircle"}, {0x1e70, "Tcircumflexbelow"}, {0x0162, "Tcommaaccent"}, {0x1e6a, "Tdotaccent"}, {0x1e6c, "Tdotbelow"}, {0x0422, "Tecyrillic"}, {0x04ac, "Tedescendercyrillic"}, {0x2169, "Tenroman"}, {0x04b4, "Tetsecyrillic"}, {0x0398, "Theta"}, {0x01ac, "Thook"}, {0x00de, "Thorn"}, {0xf7fe, "Thornsmall"}, {0x2162, "Threeroman"}, {0xf6fe, "Tildesmall"}, {0x054f, "Tiwnarmenian"}, {0x1e6e, "Tlinebelow"}, {0xff34, "Tmonospace"}, {0x0539, "Toarmenian"}, {0x01bc, "Tonefive"}, {0x0184, "Tonesix"}, {0x01a7, "Tonetwo"}, {0x01ae, "Tretroflexhook"}, {0x0426, "Tsecyrillic"}, {0x040b, "Tshecyrillic"}, {0xf774, "Tsmall"}, {0x216b, "Twelveroman"}, {0x2161, "Tworoman"}, {0x0055, "U"}, {0x00da, "Uacute"}, {0xf7fa, "Uacutesmall"}, {0x016c, "Ubreve"}, {0x01d3, "Ucaron"}, {0x24ca, "Ucircle"}, {0x00db, "Ucircumflex"}, {0x1e76, "Ucircumflexbelow"}, {0xf7fb, "Ucircumflexsmall"}, {0x0423, "Ucyrillic"}, {0x0170, "Udblacute"}, {0x0214, "Udblgrave"}, {0x00dc, "Udieresis"}, {0x01d7, "Udieresisacute"}, {0x1e72, "Udieresisbelow"}, {0x01d9, "Udieresiscaron"}, {0x04f0, "Udieresiscyrillic"}, {0x01db, "Udieresisgrave"}, {0x01d5, "Udieresismacron"}, {0xf7fc, "Udieresissmall"}, {0x1ee4, "Udotbelow"}, {0x00d9, "Ugrave"}, {0xf7f9, "Ugravesmall"}, {0x1ee6, "Uhookabove"}, {0x01af, "Uhorn"}, {0x1ee8, "Uhornacute"}, {0x1ef0, "Uhorndotbelow"}, {0x1eea, "Uhorngrave"}, {0x1eec, "Uhornhookabove"}, {0x1eee, "Uhorntilde"}, {0x0170, "Uhungarumlaut"}, {0x04f2, "Uhungarumlautcyrillic"}, {0x0216, "Uinvertedbreve"}, {0x0478, "Ukcyrillic"}, {0x016a, "Umacron"}, {0x04ee, "Umacroncyrillic"}, {0x1e7a, "Umacrondieresis"}, {0xff35, "Umonospace"}, {0x0172, "Uogonek"}, {0x03a5, "Upsilon"}, {0x03d2, "Upsilon1"}, {0x03d3, "Upsilonacutehooksymbolgreek"}, {0x01b1, "Upsilonafrican"}, {0x03ab, "Upsilondieresis"}, {0x03d4, "Upsilondieresishooksymbolgreek"}, {0x03d2, "Upsilonhooksymbol"}, {0x038e, "Upsilontonos"}, {0x016e, "Uring"}, {0x040e, "Ushortcyrillic"}, {0xf775, "Usmall"}, {0x04ae, "Ustraightcyrillic"}, {0x04b0, "Ustraightstrokecyrillic"}, {0x0168, "Utilde"}, {0x1e78, "Utildeacute"}, {0x1e74, "Utildebelow"}, {0x0056, "V"}, {0x24cb, "Vcircle"}, {0x1e7e, "Vdotbelow"}, {0x0412, "Vecyrillic"}, {0x054e, "Vewarmenian"}, {0x01b2, "Vhook"}, {0xff36, "Vmonospace"}, {0x0548, "Voarmenian"}, {0xf776, "Vsmall"}, {0x1e7c, "Vtilde"}, {0x0057, "W"}, {0x1e82, "Wacute"}, {0x24cc, "Wcircle"}, {0x0174, "Wcircumflex"}, {0x1e84, "Wdieresis"}, {0x1e86, "Wdotaccent"}, {0x1e88, "Wdotbelow"}, {0x1e80, "Wgrave"}, {0xff37, "Wmonospace"}, {0xf777, "Wsmall"}, {0x0058, "X"}, {0x24cd, "Xcircle"}, {0x1e8c, "Xdieresis"}, {0x1e8a, "Xdotaccent"}, {0x053d, "Xeharmenian"}, {0x039e, "Xi"}, {0xff38, "Xmonospace"}, {0xf778, "Xsmall"}, {0x0059, "Y"}, {0x00dd, "Yacute"}, {0xf7fd, "Yacutesmall"}, {0x0462, "Yatcyrillic"}, {0x24ce, "Ycircle"}, {0x0176, "Ycircumflex"}, {0x0178, "Ydieresis"}, {0xf7ff, "Ydieresissmall"}, {0x1e8e, "Ydotaccent"}, {0x1ef4, "Ydotbelow"}, {0x042b, "Yericyrillic"}, {0x04f8, "Yerudieresiscyrillic"}, {0x1ef2, "Ygrave"}, {0x01b3, "Yhook"}, {0x1ef6, "Yhookabove"}, {0x0545, "Yiarmenian"}, {0x0407, "Yicyrillic"}, {0x0552, "Yiwnarmenian"}, {0xff39, "Ymonospace"}, {0xf779, "Ysmall"}, {0x1ef8, "Ytilde"}, {0x046a, "Yusbigcyrillic"}, {0x046c, "Yusbigiotifiedcyrillic"}, {0x0466, "Yuslittlecyrillic"}, {0x0468, "Yuslittleiotifiedcyrillic"}, {0x005a, "Z"}, {0x0536, "Zaarmenian"}, {0x0179, "Zacute"}, {0x017d, "Zcaron"}, {0xf6ff, "Zcaronsmall"}, {0x24cf, "Zcircle"}, {0x1e90, "Zcircumflex"}, {0x017b, "Zdot"}, {0x017b, "Zdotaccent"}, {0x1e92, "Zdotbelow"}, {0x0417, "Zecyrillic"}, {0x0498, "Zedescendercyrillic"}, {0x04de, "Zedieresiscyrillic"}, {0x0396, "Zeta"}, {0x053a, "Zhearmenian"}, {0x04c1, "Zhebrevecyrillic"}, {0x0416, "Zhecyrillic"}, {0x0496, "Zhedescendercyrillic"}, {0x04dc, "Zhedieresiscyrillic"}, {0x1e94, "Zlinebelow"}, {0xff3a, "Zmonospace"}, {0xf77a, "Zsmall"}, {0x01b5, "Zstroke"}, {0x0022, "\""}, {0x005c, "\\"}, {0x005d, "]"}, {0x005e, "^"}, {0x005f, "_"}, {0x0060, "`"}, {0x0061, "a"}, {0x0986, "aabengali"}, {0x00e1, "aacute"}, {0x0906, "aadeva"}, {0x0a86, "aagujarati"}, {0x0a06, "aagurmukhi"}, {0x0a3e, "aamatragurmukhi"}, {0x3303, "aarusquare"}, {0x09be, "aavowelsignbengali"}, {0x093e, "aavowelsigndeva"}, {0x0abe, "aavowelsigngujarati"}, {0x055f, "abbreviationmarkarmenian"}, {0x0970, "abbreviationsigndeva"}, {0x0985, "abengali"}, {0x311a, "abopomofo"}, {0x0103, "abreve"}, {0x1eaf, "abreveacute"}, {0x04d1, "abrevecyrillic"}, {0x1eb7, "abrevedotbelow"}, {0x1eb1, "abrevegrave"}, {0x1eb3, "abrevehookabove"}, {0x1eb5, "abrevetilde"}, {0x01ce, "acaron"}, {0x24d0, "acircle"}, {0x00e2, "acircumflex"}, {0x1ea5, "acircumflexacute"}, {0x1ead, "acircumflexdotbelow"}, {0x1ea7, "acircumflexgrave"}, {0x1ea9, "acircumflexhookabove"}, {0x1eab, "acircumflextilde"}, {0x00b4, "acute"}, {0x0317, "acutebelowcmb"}, {0x0301, "acutecmb"}, {0x0301, "acutecomb"}, {0x0954, "acutedeva"}, {0x02cf, "acutelowmod"}, {0x0341, "acutetonecmb"}, {0x0430, "acyrillic"}, {0x0201, "adblgrave"}, {0x0a71, "addakgurmukhi"}, {0x0905, "adeva"}, {0x00e4, "adieresis"}, {0x04d3, "adieresiscyrillic"}, {0x01df, "adieresismacron"}, {0x1ea1, "adotbelow"}, {0x01e1, "adotmacron"}, {0x00e6, "ae"}, {0x01fd, "aeacute"}, {0x3150, "aekorean"}, {0x01e3, "aemacron"}, {0x2015, "afii00208"}, {0x20a4, "afii08941"}, {0x0410, "afii10017"}, {0x0411, "afii10018"}, {0x0412, "afii10019"}, {0x0413, "afii10020"}, {0x0414, "afii10021"}, {0x0415, "afii10022"}, {0x0401, "afii10023"}, {0x0416, "afii10024"}, {0x0417, "afii10025"}, {0x0418, "afii10026"}, {0x0419, "afii10027"}, {0x041a, "afii10028"}, {0x041b, "afii10029"}, {0x041c, "afii10030"}, {0x041d, "afii10031"}, {0x041e, "afii10032"}, {0x041f, "afii10033"}, {0x0420, "afii10034"}, {0x0421, "afii10035"}, {0x0422, "afii10036"}, {0x0423, "afii10037"}, {0x0424, "afii10038"}, {0x0425, "afii10039"}, {0x0426, "afii10040"}, {0x0427, "afii10041"}, {0x0428, "afii10042"}, {0x0429, "afii10043"}, {0x042a, "afii10044"}, {0x042b, "afii10045"}, {0x042c, "afii10046"}, {0x042d, "afii10047"}, {0x042e, "afii10048"}, {0x042f, "afii10049"}, {0x0490, "afii10050"}, {0x0402, "afii10051"}, {0x0403, "afii10052"}, {0x0404, "afii10053"}, {0x0405, "afii10054"}, {0x0406, "afii10055"}, {0x0407, "afii10056"}, {0x0408, "afii10057"}, {0x0409, "afii10058"}, {0x040a, "afii10059"}, {0x040b, "afii10060"}, {0x040c, "afii10061"}, {0x040e, "afii10062"}, {0xf6c4, "afii10063"}, {0xf6c5, "afii10064"}, {0x0430, "afii10065"}, {0x0431, "afii10066"}, {0x0432, "afii10067"}, {0x0433, "afii10068"}, {0x0434, "afii10069"}, {0x0435, "afii10070"}, {0x0451, "afii10071"}, {0x0436, "afii10072"}, {0x0437, "afii10073"}, {0x0438, "afii10074"}, {0x0439, "afii10075"}, {0x043a, "afii10076"}, {0x043b, "afii10077"}, {0x043c, "afii10078"}, {0x043d, "afii10079"}, {0x043e, "afii10080"}, {0x043f, "afii10081"}, {0x0440, "afii10082"}, {0x0441, "afii10083"}, {0x0442, "afii10084"}, {0x0443, "afii10085"}, {0x0444, "afii10086"}, {0x0445, "afii10087"}, {0x0446, "afii10088"}, {0x0447, "afii10089"}, {0x0448, "afii10090"}, {0x0449, "afii10091"}, {0x044a, "afii10092"}, {0x044b, "afii10093"}, {0x044c, "afii10094"}, {0x044d, "afii10095"}, {0x044e, "afii10096"}, {0x044f, "afii10097"}, {0x0491, "afii10098"}, {0x0452, "afii10099"}, {0x0453, "afii10100"}, {0x0454, "afii10101"}, {0x0455, "afii10102"}, {0x0456, "afii10103"}, {0x0457, "afii10104"}, {0x0458, "afii10105"}, {0x0459, "afii10106"}, {0x045a, "afii10107"}, {0x045b, "afii10108"}, {0x045c, "afii10109"}, {0x045e, "afii10110"}, {0x040f, "afii10145"}, {0x0462, "afii10146"}, {0x0472, "afii10147"}, {0x0474, "afii10148"}, {0xf6c6, "afii10192"}, {0x045f, "afii10193"}, {0x0463, "afii10194"}, {0x0473, "afii10195"}, {0x0475, "afii10196"}, {0xf6c7, "afii10831"}, {0xf6c8, "afii10832"}, {0x04d9, "afii10846"}, {0x200e, "afii299"}, {0x200f, "afii300"}, {0x200d, "afii301"}, {0x066a, "afii57381"}, {0x060c, "afii57388"}, {0x0660, "afii57392"}, {0x0661, "afii57393"}, {0x0662, "afii57394"}, {0x0663, "afii57395"}, {0x0664, "afii57396"}, {0x0665, "afii57397"}, {0x0666, "afii57398"}, {0x0667, "afii57399"}, {0x0668, "afii57400"}, {0x0669, "afii57401"}, {0x061b, "afii57403"}, {0x061f, "afii57407"}, {0x0621, "afii57409"}, {0x0622, "afii57410"}, {0x0623, "afii57411"}, {0x0624, "afii57412"}, {0x0625, "afii57413"}, {0x0626, "afii57414"}, {0x0627, "afii57415"}, {0x0628, "afii57416"}, {0x0629, "afii57417"}, {0x062a, "afii57418"}, {0x062b, "afii57419"}, {0x062c, "afii57420"}, {0x062d, "afii57421"}, {0x062e, "afii57422"}, {0x062f, "afii57423"}, {0x0630, "afii57424"}, {0x0631, "afii57425"}, {0x0632, "afii57426"}, {0x0633, "afii57427"}, {0x0634, "afii57428"}, {0x0635, "afii57429"}, {0x0636, "afii57430"}, {0x0637, "afii57431"}, {0x0638, "afii57432"}, {0x0639, "afii57433"}, {0x063a, "afii57434"}, {0x0640, "afii57440"}, {0x0641, "afii57441"}, {0x0642, "afii57442"}, {0x0643, "afii57443"}, {0x0644, "afii57444"}, {0x0645, "afii57445"}, {0x0646, "afii57446"}, {0x0648, "afii57448"}, {0x0649, "afii57449"}, {0x064a, "afii57450"}, {0x064b, "afii57451"}, {0x064c, "afii57452"}, {0x064d, "afii57453"}, {0x064e, "afii57454"}, {0x064f, "afii57455"}, {0x0650, "afii57456"}, {0x0651, "afii57457"}, {0x0652, "afii57458"}, {0x0647, "afii57470"}, {0x06a4, "afii57505"}, {0x067e, "afii57506"}, {0x0686, "afii57507"}, {0x0698, "afii57508"}, {0x06af, "afii57509"}, {0x0679, "afii57511"}, {0x0688, "afii57512"}, {0x0691, "afii57513"}, {0x06ba, "afii57514"}, {0x06d2, "afii57519"}, {0x06d5, "afii57534"}, {0x20aa, "afii57636"}, {0x05be, "afii57645"}, {0x05c3, "afii57658"}, {0x05d0, "afii57664"}, {0x05d1, "afii57665"}, {0x05d2, "afii57666"}, {0x05d3, "afii57667"}, {0x05d4, "afii57668"}, {0x05d5, "afii57669"}, {0x05d6, "afii57670"}, {0x05d7, "afii57671"}, {0x05d8, "afii57672"}, {0x05d9, "afii57673"}, {0x05da, "afii57674"}, {0x05db, "afii57675"}, {0x05dc, "afii57676"}, {0x05dd, "afii57677"}, {0x05de, "afii57678"}, {0x05df, "afii57679"}, {0x05e0, "afii57680"}, {0x05e1, "afii57681"}, {0x05e2, "afii57682"}, {0x05e3, "afii57683"}, {0x05e4, "afii57684"}, {0x05e5, "afii57685"}, {0x05e6, "afii57686"}, {0x05e7, "afii57687"}, {0x05e8, "afii57688"}, {0x05e9, "afii57689"}, {0x05ea, "afii57690"}, {0xfb2a, "afii57694"}, {0xfb2b, "afii57695"}, {0xfb4b, "afii57700"}, {0xfb1f, "afii57705"}, {0x05f0, "afii57716"}, {0x05f1, "afii57717"}, {0x05f2, "afii57718"}, {0xfb35, "afii57723"}, {0x05b4, "afii57793"}, {0x05b5, "afii57794"}, {0x05b6, "afii57795"}, {0x05bb, "afii57796"}, {0x05b8, "afii57797"}, {0x05b7, "afii57798"}, {0x05b0, "afii57799"}, {0x05b2, "afii57800"}, {0x05b1, "afii57801"}, {0x05b3, "afii57802"}, {0x05c2, "afii57803"}, {0x05c1, "afii57804"}, {0x05b9, "afii57806"}, {0x05bc, "afii57807"}, {0x05bd, "afii57839"}, {0x05bf, "afii57841"}, {0x05c0, "afii57842"}, {0x02bc, "afii57929"}, {0x2105, "afii61248"}, {0x2113, "afii61289"}, {0x2116, "afii61352"}, {0x202c, "afii61573"}, {0x202d, "afii61574"}, {0x202e, "afii61575"}, {0x200c, "afii61664"}, {0x066d, "afii63167"}, {0x02bd, "afii64937"}, {0x00e0, "agrave"}, {0x0a85, "agujarati"}, {0x0a05, "agurmukhi"}, {0x3042, "ahiragana"}, {0x1ea3, "ahookabove"}, {0x0990, "aibengali"}, {0x311e, "aibopomofo"}, {0x0910, "aideva"}, {0x04d5, "aiecyrillic"}, {0x0a90, "aigujarati"}, {0x0a10, "aigurmukhi"}, {0x0a48, "aimatragurmukhi"}, {0x0639, "ainarabic"}, {0xfeca, "ainfinalarabic"}, {0xfecb, "aininitialarabic"}, {0xfecc, "ainmedialarabic"}, {0x0203, "ainvertedbreve"}, {0x09c8, "aivowelsignbengali"}, {0x0948, "aivowelsigndeva"}, {0x0ac8, "aivowelsigngujarati"}, {0x30a2, "akatakana"}, {0xff71, "akatakanahalfwidth"}, {0x314f, "akorean"}, {0x05d0, "alef"}, {0x0627, "alefarabic"}, {0xfb30, "alefdageshhebrew"}, {0xfe8e, "aleffinalarabic"}, {0x0623, "alefhamzaabovearabic"}, {0xfe84, "alefhamzaabovefinalarabic"}, {0x0625, "alefhamzabelowarabic"}, {0xfe88, "alefhamzabelowfinalarabic"}, {0x05d0, "alefhebrew"}, {0xfb4f, "aleflamedhebrew"}, {0x0622, "alefmaddaabovearabic"}, {0xfe82, "alefmaddaabovefinalarabic"}, {0x0649, "alefmaksuraarabic"}, {0xfef0, "alefmaksurafinalarabic"}, {0xfef3, "alefmaksurainitialarabic"}, {0xfef4, "alefmaksuramedialarabic"}, {0xfb2e, "alefpatahhebrew"}, {0xfb2f, "alefqamatshebrew"}, {0x2135, "aleph"}, {0x224c, "allequal"}, {0x03b1, "alpha"}, {0x03ac, "alphatonos"}, {0x0101, "amacron"}, {0xff41, "amonospace"}, {0x0026, "ampersand"}, {0xff06, "ampersandmonospace"}, {0xf726, "ampersandsmall"}, {0x33c2, "amsquare"}, {0x3122, "anbopomofo"}, {0x3124, "angbopomofo"}, {0x0e5a, "angkhankhuthai"}, {0x2220, "angle"}, {0x3008, "anglebracketleft"}, {0xfe3f, "anglebracketleftvertical"}, {0x3009, "anglebracketright"}, {0xfe40, "anglebracketrightvertical"}, {0x2329, "angleleft"}, {0x232a, "angleright"}, {0x212b, "angstrom"}, {0x0387, "anoteleia"}, {0x0952, "anudattadeva"}, {0x0982, "anusvarabengali"}, {0x0902, "anusvaradeva"}, {0x0a82, "anusvaragujarati"}, {0x0105, "aogonek"}, {0x3300, "apaatosquare"}, {0x249c, "aparen"}, {0x055a, "apostrophearmenian"}, {0x02bc, "apostrophemod"}, {0xf8ff, "apple"}, {0x2250, "approaches"}, {0x2248, "approxequal"}, {0x2252, "approxequalorimage"}, {0x2245, "approximatelyequal"}, {0x318e, "araeaekorean"}, {0x318d, "araeakorean"}, {0x2312, "arc"}, {0x1e9a, "arighthalfring"}, {0x00e5, "aring"}, {0x01fb, "aringacute"}, {0x1e01, "aringbelow"}, {0x2194, "arrowboth"}, {0x21e3, "arrowdashdown"}, {0x21e0, "arrowdashleft"}, {0x21e2, "arrowdashright"}, {0x21e1, "arrowdashup"}, {0x21d4, "arrowdblboth"}, {0x21d3, "arrowdbldown"}, {0x21d0, "arrowdblleft"}, {0x21d2, "arrowdblright"}, {0x21d1, "arrowdblup"}, {0x2193, "arrowdown"}, {0x2199, "arrowdownleft"}, {0x2198, "arrowdownright"}, {0x21e9, "arrowdownwhite"}, {0x02c5, "arrowheaddownmod"}, {0x02c2, "arrowheadleftmod"}, {0x02c3, "arrowheadrightmod"}, {0x02c4, "arrowheadupmod"}, {0xf8e7, "arrowhorizex"}, {0x2190, "arrowleft"}, {0x21d0, "arrowleftdbl"}, {0x21cd, "arrowleftdblstroke"}, {0x21c6, "arrowleftoverright"}, {0x21e6, "arrowleftwhite"}, {0x2192, "arrowright"}, {0x21cf, "arrowrightdblstroke"}, {0x279e, "arrowrightheavy"}, {0x21c4, "arrowrightoverleft"}, {0x21e8, "arrowrightwhite"}, {0x21e4, "arrowtableft"}, {0x21e5, "arrowtabright"}, {0x2191, "arrowup"}, {0x2195, "arrowupdn"}, {0x21a8, "arrowupdnbse"}, {0x21a8, "arrowupdownbase"}, {0x2196, "arrowupleft"}, {0x21c5, "arrowupleftofdown"}, {0x2197, "arrowupright"}, {0x21e7, "arrowupwhite"}, {0xf8e6, "arrowvertex"}, {0x005e, "asciicircum"}, {0xff3e, "asciicircummonospace"}, {0x007e, "asciitilde"}, {0xff5e, "asciitildemonospace"}, {0x0251, "ascript"}, {0x0252, "ascriptturned"}, {0x3041, "asmallhiragana"}, {0x30a1, "asmallkatakana"}, {0xff67, "asmallkatakanahalfwidth"}, {0x002a, "asterisk"}, {0x066d, "asteriskaltonearabic"}, {0x066d, "asteriskarabic"}, {0x2217, "asteriskmath"}, {0xff0a, "asteriskmonospace"}, {0xfe61, "asterisksmall"}, {0x2042, "asterism"}, {0xf6e9, "asuperior"}, {0x2243, "asymptoticallyequal"}, {0x0040, "at"}, {0x00e3, "atilde"}, {0xff20, "atmonospace"}, {0xfe6b, "atsmall"}, {0x0250, "aturned"}, {0x0994, "aubengali"}, {0x3120, "aubopomofo"}, {0x0914, "audeva"}, {0x0a94, "augujarati"}, {0x0a14, "augurmukhi"}, {0x09d7, "aulengthmarkbengali"}, {0x0a4c, "aumatragurmukhi"}, {0x09cc, "auvowelsignbengali"}, {0x094c, "auvowelsigndeva"}, {0x0acc, "auvowelsigngujarati"}, {0x093d, "avagrahadeva"}, {0x0561, "aybarmenian"}, {0x05e2, "ayin"}, {0xfb20, "ayinaltonehebrew"}, {0x05e2, "ayinhebrew"}, {0x0062, "b"}, {0x09ac, "babengali"}, {0x005c, "backslash"}, {0xff3c, "backslashmonospace"}, {0x092c, "badeva"}, {0x0aac, "bagujarati"}, {0x0a2c, "bagurmukhi"}, {0x3070, "bahiragana"}, {0x0e3f, "bahtthai"}, {0x30d0, "bakatakana"}, {0x007c, "bar"}, {0xff5c, "barmonospace"}, {0x3105, "bbopomofo"}, {0x24d1, "bcircle"}, {0x1e03, "bdotaccent"}, {0x1e05, "bdotbelow"}, {0x266c, "beamedsixteenthnotes"}, {0x2235, "because"}, {0x0431, "becyrillic"}, {0x0628, "beharabic"}, {0xfe90, "behfinalarabic"}, {0xfe91, "behinitialarabic"}, {0x3079, "behiragana"}, {0xfe92, "behmedialarabic"}, {0xfc9f, "behmeeminitialarabic"}, {0xfc08, "behmeemisolatedarabic"}, {0xfc6d, "behnoonfinalarabic"}, {0x30d9, "bekatakana"}, {0x0562, "benarmenian"}, {0x05d1, "bet"}, {0x03b2, "beta"}, {0x03d0, "betasymbolgreek"}, {0xfb31, "betdagesh"}, {0xfb31, "betdageshhebrew"}, {0x05d1, "bethebrew"}, {0xfb4c, "betrafehebrew"}, {0x09ad, "bhabengali"}, {0x092d, "bhadeva"}, {0x0aad, "bhagujarati"}, {0x0a2d, "bhagurmukhi"}, {0x0253, "bhook"}, {0x3073, "bihiragana"}, {0x30d3, "bikatakana"}, {0x0298, "bilabialclick"}, {0x0a02, "bindigurmukhi"}, {0x3331, "birusquare"}, {0x25cf, "blackcircle"}, {0x25c6, "blackdiamond"}, {0x25bc, "blackdownpointingtriangle"}, {0x25c4, "blackleftpointingpointer"}, {0x25c0, "blackleftpointingtriangle"}, {0x3010, "blacklenticularbracketleft"}, {0xfe3b, "blacklenticularbracketleftvertical"}, {0x3011, "blacklenticularbracketright"}, {0xfe3c, "blacklenticularbracketrightvertical"}, {0x25e3, "blacklowerlefttriangle"}, {0x25e2, "blacklowerrighttriangle"}, {0x25ac, "blackrectangle"}, {0x25ba, "blackrightpointingpointer"}, {0x25b6, "blackrightpointingtriangle"}, {0x25aa, "blacksmallsquare"}, {0x263b, "blacksmilingface"}, {0x25a0, "blacksquare"}, {0x2605, "blackstar"}, {0x25e4, "blackupperlefttriangle"}, {0x25e5, "blackupperrighttriangle"}, {0x25b4, "blackuppointingsmalltriangle"}, {0x25b2, "blackuppointingtriangle"}, {0x2423, "blank"}, {0x1e07, "blinebelow"}, {0x2588, "block"}, {0xff42, "bmonospace"}, {0x0e1a, "bobaimaithai"}, {0x307c, "bohiragana"}, {0x30dc, "bokatakana"}, {0x249d, "bparen"}, {0x33c3, "bqsquare"}, {0xf8f4, "braceex"}, {0x007b, "braceleft"}, {0xf8f3, "braceleftbt"}, {0xf8f2, "braceleftmid"}, {0xff5b, "braceleftmonospace"}, {0xfe5b, "braceleftsmall"}, {0xf8f1, "bracelefttp"}, {0xfe37, "braceleftvertical"}, {0x007d, "braceright"}, {0xf8fe, "bracerightbt"}, {0xf8fd, "bracerightmid"}, {0xff5d, "bracerightmonospace"}, {0xfe5c, "bracerightsmall"}, {0xf8fc, "bracerighttp"}, {0xfe38, "bracerightvertical"}, {0x005b, "bracketleft"}, {0xf8f0, "bracketleftbt"}, {0xf8ef, "bracketleftex"}, {0xff3b, "bracketleftmonospace"}, {0xf8ee, "bracketlefttp"}, {0x005d, "bracketright"}, {0xf8fb, "bracketrightbt"}, {0xf8fa, "bracketrightex"}, {0xff3d, "bracketrightmonospace"}, {0xf8f9, "bracketrighttp"}, {0x02d8, "breve"}, {0x032e, "brevebelowcmb"}, {0x0306, "brevecmb"}, {0x032f, "breveinvertedbelowcmb"}, {0x0311, "breveinvertedcmb"}, {0x0361, "breveinverteddoublecmb"}, {0x032a, "bridgebelowcmb"}, {0x033a, "bridgeinvertedbelowcmb"}, {0x00a6, "brokenbar"}, {0x0180, "bstroke"}, {0xf6ea, "bsuperior"}, {0x0183, "btopbar"}, {0x3076, "buhiragana"}, {0x30d6, "bukatakana"}, {0x2022, "bullet"}, {0x25d8, "bulletinverse"}, {0x2219, "bulletoperator"}, {0x25ce, "bullseye"}, {0x0063, "c"}, {0x056e, "caarmenian"}, {0x099a, "cabengali"}, {0x0107, "cacute"}, {0x091a, "cadeva"}, {0x0a9a, "cagujarati"}, {0x0a1a, "cagurmukhi"}, {0x3388, "calsquare"}, {0x0981, "candrabindubengali"}, {0x0310, "candrabinducmb"}, {0x0901, "candrabindudeva"}, {0x0a81, "candrabindugujarati"}, {0x21ea, "capslock"}, {0x2105, "careof"}, {0x02c7, "caron"}, {0x032c, "caronbelowcmb"}, {0x030c, "caroncmb"}, {0x21b5, "carriagereturn"}, {0x3118, "cbopomofo"}, {0x010d, "ccaron"}, {0x00e7, "ccedilla"}, {0x1e09, "ccedillaacute"}, {0x24d2, "ccircle"}, {0x0109, "ccircumflex"}, {0x0255, "ccurl"}, {0x010b, "cdot"}, {0x010b, "cdotaccent"}, {0x33c5, "cdsquare"}, {0x00b8, "cedilla"}, {0x0327, "cedillacmb"}, {0x00a2, "cent"}, {0x2103, "centigrade"}, {0xf6df, "centinferior"}, {0xffe0, "centmonospace"}, {0xf7a2, "centoldstyle"}, {0xf6e0, "centsuperior"}, {0x0579, "chaarmenian"}, {0x099b, "chabengali"}, {0x091b, "chadeva"}, {0x0a9b, "chagujarati"}, {0x0a1b, "chagurmukhi"}, {0x3114, "chbopomofo"}, {0x04bd, "cheabkhasiancyrillic"}, {0x2713, "checkmark"}, {0x0447, "checyrillic"}, {0x04bf, "chedescenderabkhasiancyrillic"}, {0x04b7, "chedescendercyrillic"}, {0x04f5, "chedieresiscyrillic"}, {0x0573, "cheharmenian"}, {0x04cc, "chekhakassiancyrillic"}, {0x04b9, "cheverticalstrokecyrillic"}, {0x03c7, "chi"}, {0x3277, "chieuchacirclekorean"}, {0x3217, "chieuchaparenkorean"}, {0x3269, "chieuchcirclekorean"}, {0x314a, "chieuchkorean"}, {0x3209, "chieuchparenkorean"}, {0x0e0a, "chochangthai"}, {0x0e08, "chochanthai"}, {0x0e09, "chochingthai"}, {0x0e0c, "chochoethai"}, {0x0188, "chook"}, {0x3276, "cieucacirclekorean"}, {0x3216, "cieucaparenkorean"}, {0x3268, "cieuccirclekorean"}, {0x3148, "cieuckorean"}, {0x3208, "cieucparenkorean"}, {0x321c, "cieucuparenkorean"}, {0x25cb, "circle"}, {0x2297, "circlemultiply"}, {0x2299, "circleot"}, {0x2295, "circleplus"}, {0x3036, "circlepostalmark"}, {0x25d0, "circlewithlefthalfblack"}, {0x25d1, "circlewithrighthalfblack"}, {0x02c6, "circumflex"}, {0x032d, "circumflexbelowcmb"}, {0x0302, "circumflexcmb"}, {0x2327, "clear"}, {0x01c2, "clickalveolar"}, {0x01c0, "clickdental"}, {0x01c1, "clicklateral"}, {0x01c3, "clickretroflex"}, {0x2663, "club"}, {0x2663, "clubsuitblack"}, {0x2667, "clubsuitwhite"}, {0x33a4, "cmcubedsquare"}, {0xff43, "cmonospace"}, {0x33a0, "cmsquaredsquare"}, {0x0581, "coarmenian"}, {0x003a, "colon"}, {0x20a1, "colonmonetary"}, {0xff1a, "colonmonospace"}, {0x20a1, "colonsign"}, {0xfe55, "colonsmall"}, {0x02d1, "colontriangularhalfmod"}, {0x02d0, "colontriangularmod"}, {0x002c, "comma"}, {0x0313, "commaabovecmb"}, {0x0315, "commaaboverightcmb"}, {0xf6c3, "commaaccent"}, {0x060c, "commaarabic"}, {0x055d, "commaarmenian"}, {0xf6e1, "commainferior"}, {0xff0c, "commamonospace"}, {0x0314, "commareversedabovecmb"}, {0x02bd, "commareversedmod"}, {0xfe50, "commasmall"}, {0xf6e2, "commasuperior"}, {0x0312, "commaturnedabovecmb"}, {0x02bb, "commaturnedmod"}, {0x263c, "compass"}, {0x2245, "congruent"}, {0x222e, "contourintegral"}, {0x2303, "control"}, {0x0006, "controlACK"}, {0x0007, "controlBEL"}, {0x0008, "controlBS"}, {0x0018, "controlCAN"}, {0x000d, "controlCR"}, {0x0011, "controlDC1"}, {0x0012, "controlDC2"}, {0x0013, "controlDC3"}, {0x0014, "controlDC4"}, {0x007f, "controlDEL"}, {0x0010, "controlDLE"}, {0x0019, "controlEM"}, {0x0005, "controlENQ"}, {0x0004, "controlEOT"}, {0x001b, "controlESC"}, {0x0017, "controlETB"}, {0x0003, "controlETX"}, {0x000c, "controlFF"}, {0x001c, "controlFS"}, {0x001d, "controlGS"}, {0x0009, "controlHT"}, {0x000a, "controlLF"}, {0x0015, "controlNAK"}, {0x001e, "controlRS"}, {0x000f, "controlSI"}, {0x000e, "controlSO"}, {0x0002, "controlSOT"}, {0x0001, "controlSTX"}, {0x001a, "controlSUB"}, {0x0016, "controlSYN"}, {0x001f, "controlUS"}, {0x000b, "controlVT"}, {0x00a9, "copyright"}, {0x00a9, "copyrightsans"}, {0x00a9, "copyrightserif"}, {0x300c, "cornerbracketleft"}, {0xff62, "cornerbracketlefthalfwidth"}, {0xfe41, "cornerbracketleftvertical"}, {0x300d, "cornerbracketright"}, {0xff63, "cornerbracketrighthalfwidth"}, {0xfe42, "cornerbracketrightvertical"}, {0x337f, "corporationsquare"}, {0x33c7, "cosquare"}, {0x33c6, "coverkgsquare"}, {0x249e, "cparen"}, {0x20a2, "cruzeiro"}, {0x0297, "cstretched"}, {0x22cf, "curlyand"}, {0x22ce, "curlyor"}, {0x00a4, "currency"}, {0xf6d1, "cyrBreve"}, {0xf6d2, "cyrFlex"}, {0xf6d4, "cyrbreve"}, {0xf6d5, "cyrflex"}, {0x0064, "d"}, {0x0564, "daarmenian"}, {0x09a6, "dabengali"}, {0x0636, "dadarabic"}, {0x0926, "dadeva"}, {0xfebe, "dadfinalarabic"}, {0xfebf, "dadinitialarabic"}, {0xfec0, "dadmedialarabic"}, {0x05bc, "dagesh"}, {0x05bc, "dageshhebrew"}, {0x2020, "dagger"}, {0x2021, "daggerdbl"}, {0x0aa6, "dagujarati"}, {0x0a26, "dagurmukhi"}, {0x3060, "dahiragana"}, {0x30c0, "dakatakana"}, {0x062f, "dalarabic"}, {0x05d3, "dalet"}, {0xfb33, "daletdagesh"}, {0xfb33, "daletdageshhebrew"}, {0x05d3, "dalethebrew"}, {0xfeaa, "dalfinalarabic"}, {0x064f, "dammaarabic"}, {0x064f, "dammalowarabic"}, {0x064c, "dammatanaltonearabic"}, {0x064c, "dammatanarabic"}, {0x0964, "danda"}, {0x05a7, "dargahebrew"}, {0x05a7, "dargalefthebrew"}, {0x0485, "dasiapneumatacyrilliccmb"}, {0xf6d3, "dblGrave"}, {0x300a, "dblanglebracketleft"}, {0xfe3d, "dblanglebracketleftvertical"}, {0x300b, "dblanglebracketright"}, {0xfe3e, "dblanglebracketrightvertical"}, {0x032b, "dblarchinvertedbelowcmb"}, {0x21d4, "dblarrowleft"}, {0x21d2, "dblarrowright"}, {0x0965, "dbldanda"}, {0xf6d6, "dblgrave"}, {0x030f, "dblgravecmb"}, {0x222c, "dblintegral"}, {0x2017, "dbllowline"}, {0x0333, "dbllowlinecmb"}, {0x033f, "dbloverlinecmb"}, {0x02ba, "dblprimemod"}, {0x2016, "dblverticalbar"}, {0x030e, "dblverticallineabovecmb"}, {0x3109, "dbopomofo"}, {0x33c8, "dbsquare"}, {0x010f, "dcaron"}, {0x1e11, "dcedilla"}, {0x24d3, "dcircle"}, {0x1e13, "dcircumflexbelow"}, {0x0111, "dcroat"}, {0x09a1, "ddabengali"}, {0x0921, "ddadeva"}, {0x0aa1, "ddagujarati"}, {0x0a21, "ddagurmukhi"}, {0x0688, "ddalarabic"}, {0xfb89, "ddalfinalarabic"}, {0x095c, "dddhadeva"}, {0x09a2, "ddhabengali"}, {0x0922, "ddhadeva"}, {0x0aa2, "ddhagujarati"}, {0x0a22, "ddhagurmukhi"}, {0x1e0b, "ddotaccent"}, {0x1e0d, "ddotbelow"}, {0x066b, "decimalseparatorarabic"}, {0x066b, "decimalseparatorpersian"}, {0x0434, "decyrillic"}, {0x00b0, "degree"}, {0x05ad, "dehihebrew"}, {0x3067, "dehiragana"}, {0x03ef, "deicoptic"}, {0x30c7, "dekatakana"}, {0x232b, "deleteleft"}, {0x2326, "deleteright"}, {0x03b4, "delta"}, {0x018d, "deltaturned"}, {0x09f8, "denominatorminusonenumeratorbengali"}, {0x02a4, "dezh"}, {0x09a7, "dhabengali"}, {0x0927, "dhadeva"}, {0x0aa7, "dhagujarati"}, {0x0a27, "dhagurmukhi"}, {0x0257, "dhook"}, {0x0385, "dialytikatonos"}, {0x0344, "dialytikatonoscmb"}, {0x2666, "diamond"}, {0x2662, "diamondsuitwhite"}, {0x00a8, "dieresis"}, {0xf6d7, "dieresisacute"}, {0x0324, "dieresisbelowcmb"}, {0x0308, "dieresiscmb"}, {0xf6d8, "dieresisgrave"}, {0x0385, "dieresistonos"}, {0x3062, "dihiragana"}, {0x30c2, "dikatakana"}, {0x3003, "dittomark"}, {0x00f7, "divide"}, {0x2223, "divides"}, {0x2215, "divisionslash"}, {0x0452, "djecyrillic"}, {0x2593, "dkshade"}, {0x1e0f, "dlinebelow"}, {0x3397, "dlsquare"}, {0x0111, "dmacron"}, {0xff44, "dmonospace"}, {0x2584, "dnblock"}, {0x0e0e, "dochadathai"}, {0x0e14, "dodekthai"}, {0x3069, "dohiragana"}, {0x30c9, "dokatakana"}, {0x0024, "dollar"}, {0xf6e3, "dollarinferior"}, {0xff04, "dollarmonospace"}, {0xf724, "dollaroldstyle"}, {0xfe69, "dollarsmall"}, {0xf6e4, "dollarsuperior"}, {0x20ab, "dong"}, {0x3326, "dorusquare"}, {0x02d9, "dotaccent"}, {0x0307, "dotaccentcmb"}, {0x0323, "dotbelowcmb"}, {0x0323, "dotbelowcomb"}, {0x30fb, "dotkatakana"}, {0x0131, "dotlessi"}, {0xf6be, "dotlessj"}, {0x0284, "dotlessjstrokehook"}, {0x22c5, "dotmath"}, {0x25cc, "dottedcircle"}, {0xfb1f, "doubleyodpatah"}, {0xfb1f, "doubleyodpatahhebrew"}, {0x031e, "downtackbelowcmb"}, {0x02d5, "downtackmod"}, {0x249f, "dparen"}, {0xf6eb, "dsuperior"}, {0x0256, "dtail"}, {0x018c, "dtopbar"}, {0x3065, "duhiragana"}, {0x30c5, "dukatakana"}, {0x01f3, "dz"}, {0x02a3, "dzaltone"}, {0x01c6, "dzcaron"}, {0x02a5, "dzcurl"}, {0x04e1, "dzeabkhasiancyrillic"}, {0x0455, "dzecyrillic"}, {0x045f, "dzhecyrillic"}, {0x0065, "e"}, {0x00e9, "eacute"}, {0x2641, "earth"}, {0x098f, "ebengali"}, {0x311c, "ebopomofo"}, {0x0115, "ebreve"}, {0x090d, "ecandradeva"}, {0x0a8d, "ecandragujarati"}, {0x0945, "ecandravowelsigndeva"}, {0x0ac5, "ecandravowelsigngujarati"}, {0x011b, "ecaron"}, {0x1e1d, "ecedillabreve"}, {0x0565, "echarmenian"}, {0x0587, "echyiwnarmenian"}, {0x24d4, "ecircle"}, {0x00ea, "ecircumflex"}, {0x1ebf, "ecircumflexacute"}, {0x1e19, "ecircumflexbelow"}, {0x1ec7, "ecircumflexdotbelow"}, {0x1ec1, "ecircumflexgrave"}, {0x1ec3, "ecircumflexhookabove"}, {0x1ec5, "ecircumflextilde"}, {0x0454, "ecyrillic"}, {0x0205, "edblgrave"}, {0x090f, "edeva"}, {0x00eb, "edieresis"}, {0x0117, "edot"}, {0x0117, "edotaccent"}, {0x1eb9, "edotbelow"}, {0x0a0f, "eegurmukhi"}, {0x0a47, "eematragurmukhi"}, {0x0444, "efcyrillic"}, {0x00e8, "egrave"}, {0x0a8f, "egujarati"}, {0x0567, "eharmenian"}, {0x311d, "ehbopomofo"}, {0x3048, "ehiragana"}, {0x1ebb, "ehookabove"}, {0x311f, "eibopomofo"}, {0x0038, "eight"}, {0x0668, "eightarabic"}, {0x09ee, "eightbengali"}, {0x2467, "eightcircle"}, {0x2791, "eightcircleinversesansserif"}, {0x096e, "eightdeva"}, {0x2471, "eighteencircle"}, {0x2485, "eighteenparen"}, {0x2499, "eighteenperiod"}, {0x0aee, "eightgujarati"}, {0x0a6e, "eightgurmukhi"}, {0x0668, "eighthackarabic"}, {0x3028, "eighthangzhou"}, {0x266b, "eighthnotebeamed"}, {0x3227, "eightideographicparen"}, {0x2088, "eightinferior"}, {0xff18, "eightmonospace"}, {0xf738, "eightoldstyle"}, {0x247b, "eightparen"}, {0x248f, "eightperiod"}, {0x06f8, "eightpersian"}, {0x2177, "eightroman"}, {0x2078, "eightsuperior"}, {0x0e58, "eightthai"}, {0x0207, "einvertedbreve"}, {0x0465, "eiotifiedcyrillic"}, {0x30a8, "ekatakana"}, {0xff74, "ekatakanahalfwidth"}, {0x0a74, "ekonkargurmukhi"}, {0x3154, "ekorean"}, {0x043b, "elcyrillic"}, {0x2208, "element"}, {0x246a, "elevencircle"}, {0x247e, "elevenparen"}, {0x2492, "elevenperiod"}, {0x217a, "elevenroman"}, {0x2026, "ellipsis"}, {0x22ee, "ellipsisvertical"}, {0x0113, "emacron"}, {0x1e17, "emacronacute"}, {0x1e15, "emacrongrave"}, {0x043c, "emcyrillic"}, {0x2014, "emdash"}, {0xfe31, "emdashvertical"}, {0xff45, "emonospace"}, {0x055b, "emphasismarkarmenian"}, {0x2205, "emptyset"}, {0x3123, "enbopomofo"}, {0x043d, "encyrillic"}, {0x2013, "endash"}, {0xfe32, "endashvertical"}, {0x04a3, "endescendercyrillic"}, {0x014b, "eng"}, {0x3125, "engbopomofo"}, {0x04a5, "enghecyrillic"}, {0x04c8, "enhookcyrillic"}, {0x2002, "enspace"}, {0x0119, "eogonek"}, {0x3153, "eokorean"}, {0x025b, "eopen"}, {0x029a, "eopenclosed"}, {0x025c, "eopenreversed"}, {0x025e, "eopenreversedclosed"}, {0x025d, "eopenreversedhook"}, {0x24a0, "eparen"}, {0x03b5, "epsilon"}, {0x03ad, "epsilontonos"}, {0x003d, "equal"}, {0xff1d, "equalmonospace"}, {0xfe66, "equalsmall"}, {0x207c, "equalsuperior"}, {0x2261, "equivalence"}, {0x3126, "erbopomofo"}, {0x0440, "ercyrillic"}, {0x0258, "ereversed"}, {0x044d, "ereversedcyrillic"}, {0x0441, "escyrillic"}, {0x04ab, "esdescendercyrillic"}, {0x0283, "esh"}, {0x0286, "eshcurl"}, {0x090e, "eshortdeva"}, {0x0946, "eshortvowelsigndeva"}, {0x01aa, "eshreversedloop"}, {0x0285, "eshsquatreversed"}, {0x3047, "esmallhiragana"}, {0x30a7, "esmallkatakana"}, {0xff6a, "esmallkatakanahalfwidth"}, {0x212e, "estimated"}, {0xf6ec, "esuperior"}, {0x03b7, "eta"}, {0x0568, "etarmenian"}, {0x03ae, "etatonos"}, {0x00f0, "eth"}, {0x1ebd, "etilde"}, {0x1e1b, "etildebelow"}, {0x0591, "etnahtafoukhhebrew"}, {0x0591, "etnahtafoukhlefthebrew"}, {0x0591, "etnahtahebrew"}, {0x0591, "etnahtalefthebrew"}, {0x01dd, "eturned"}, {0x3161, "eukorean"}, {0x20ac, "euro"}, {0x09c7, "evowelsignbengali"}, {0x0947, "evowelsigndeva"}, {0x0ac7, "evowelsigngujarati"}, {0x0021, "exclam"}, {0x055c, "exclamarmenian"}, {0x203c, "exclamdbl"}, {0x00a1, "exclamdown"}, {0xf7a1, "exclamdownsmall"}, {0x0021, "exclamleft"}, {0xff01, "exclammonospace"}, {0xf721, "exclamsmall"}, {0x2203, "existential"}, {0x0292, "ezh"}, {0x01ef, "ezhcaron"}, {0x0293, "ezhcurl"}, {0x01b9, "ezhreversed"}, {0x01ba, "ezhtail"}, {0x0066, "f"}, {0x095e, "fadeva"}, {0x0a5e, "fagurmukhi"}, {0x2109, "fahrenheit"}, {0x064e, "fathaarabic"}, {0x064e, "fathalowarabic"}, {0x064b, "fathatanarabic"}, {0x3108, "fbopomofo"}, {0x24d5, "fcircle"}, {0x1e1f, "fdotaccent"}, {0x0641, "feharabic"}, {0x0586, "feharmenian"}, {0xfed2, "fehfinalarabic"}, {0xfed3, "fehinitialarabic"}, {0xfed4, "fehmedialarabic"}, {0x03e5, "feicoptic"}, {0x2640, "female"}, {0xfb00, "ff"}, {0xfb03, "ffi"}, {0xfb04, "ffl"}, {0xfb01, "fi"}, {0x246e, "fifteencircle"}, {0x2482, "fifteenparen"}, {0x2496, "fifteenperiod"}, {0x2012, "figuredash"}, {0x25a0, "filledbox"}, {0x25ac, "filledrect"}, {0x05da, "finalkaf"}, {0xfb3a, "finalkafdagesh"}, {0xfb3a, "finalkafdageshhebrew"}, {0x05da, "finalkafhebrew"}, {0x05dd, "finalmem"}, {0x05dd, "finalmemhebrew"}, {0x05df, "finalnun"}, {0x05df, "finalnunhebrew"}, {0x05e3, "finalpe"}, {0x05e3, "finalpehebrew"}, {0x05e5, "finaltsadi"}, {0x05e5, "finaltsadihebrew"}, {0x02c9, "firsttonechinese"}, {0x25c9, "fisheye"}, {0x0473, "fitacyrillic"}, {0x0035, "five"}, {0x0665, "fivearabic"}, {0x09eb, "fivebengali"}, {0x2464, "fivecircle"}, {0x278e, "fivecircleinversesansserif"}, {0x096b, "fivedeva"}, {0x215d, "fiveeighths"}, {0x0aeb, "fivegujarati"}, {0x0a6b, "fivegurmukhi"}, {0x0665, "fivehackarabic"}, {0x3025, "fivehangzhou"}, {0x3224, "fiveideographicparen"}, {0x2085, "fiveinferior"}, {0xff15, "fivemonospace"}, {0xf735, "fiveoldstyle"}, {0x2478, "fiveparen"}, {0x248c, "fiveperiod"}, {0x06f5, "fivepersian"}, {0x2174, "fiveroman"}, {0x2075, "fivesuperior"}, {0x0e55, "fivethai"}, {0xfb02, "fl"}, {0x0192, "florin"}, {0xff46, "fmonospace"}, {0x3399, "fmsquare"}, {0x0e1f, "fofanthai"}, {0x0e1d, "fofathai"}, {0x0e4f, "fongmanthai"}, {0x2200, "forall"}, {0x0034, "four"}, {0x0664, "fourarabic"}, {0x09ea, "fourbengali"}, {0x2463, "fourcircle"}, {0x278d, "fourcircleinversesansserif"}, {0x096a, "fourdeva"}, {0x0aea, "fourgujarati"}, {0x0a6a, "fourgurmukhi"}, {0x0664, "fourhackarabic"}, {0x3024, "fourhangzhou"}, {0x3223, "fourideographicparen"}, {0x2084, "fourinferior"}, {0xff14, "fourmonospace"}, {0x09f7, "fournumeratorbengali"}, {0xf734, "fouroldstyle"}, {0x2477, "fourparen"}, {0x248b, "fourperiod"}, {0x06f4, "fourpersian"}, {0x2173, "fourroman"}, {0x2074, "foursuperior"}, {0x246d, "fourteencircle"}, {0x2481, "fourteenparen"}, {0x2495, "fourteenperiod"}, {0x0e54, "fourthai"}, {0x02cb, "fourthtonechinese"}, {0x24a1, "fparen"}, {0x2044, "fraction"}, {0x20a3, "franc"}, {0x0067, "g"}, {0x0997, "gabengali"}, {0x01f5, "gacute"}, {0x0917, "gadeva"}, {0x06af, "gafarabic"}, {0xfb93, "gaffinalarabic"}, {0xfb94, "gafinitialarabic"}, {0xfb95, "gafmedialarabic"}, {0x0a97, "gagujarati"}, {0x0a17, "gagurmukhi"}, {0x304c, "gahiragana"}, {0x30ac, "gakatakana"}, {0x03b3, "gamma"}, {0x0263, "gammalatinsmall"}, {0x02e0, "gammasuperior"}, {0x03eb, "gangiacoptic"}, {0x310d, "gbopomofo"}, {0x011f, "gbreve"}, {0x01e7, "gcaron"}, {0x0123, "gcedilla"}, {0x24d6, "gcircle"}, {0x011d, "gcircumflex"}, {0x0123, "gcommaaccent"}, {0x0121, "gdot"}, {0x0121, "gdotaccent"}, {0x0433, "gecyrillic"}, {0x3052, "gehiragana"}, {0x30b2, "gekatakana"}, {0x2251, "geometricallyequal"}, {0x059c, "gereshaccenthebrew"}, {0x05f3, "gereshhebrew"}, {0x059d, "gereshmuqdamhebrew"}, {0x00df, "germandbls"}, {0x059e, "gershayimaccenthebrew"}, {0x05f4, "gershayimhebrew"}, {0x3013, "getamark"}, {0x0998, "ghabengali"}, {0x0572, "ghadarmenian"}, {0x0918, "ghadeva"}, {0x0a98, "ghagujarati"}, {0x0a18, "ghagurmukhi"}, {0x063a, "ghainarabic"}, {0xfece, "ghainfinalarabic"}, {0xfecf, "ghaininitialarabic"}, {0xfed0, "ghainmedialarabic"}, {0x0495, "ghemiddlehookcyrillic"}, {0x0493, "ghestrokecyrillic"}, {0x0491, "gheupturncyrillic"}, {0x095a, "ghhadeva"}, {0x0a5a, "ghhagurmukhi"}, {0x0260, "ghook"}, {0x3393, "ghzsquare"}, {0x304e, "gihiragana"}, {0x30ae, "gikatakana"}, {0x0563, "gimarmenian"}, {0x05d2, "gimel"}, {0xfb32, "gimeldagesh"}, {0xfb32, "gimeldageshhebrew"}, {0x05d2, "gimelhebrew"}, {0x0453, "gjecyrillic"}, {0x01be, "glottalinvertedstroke"}, {0x0294, "glottalstop"}, {0x0296, "glottalstopinverted"}, {0x02c0, "glottalstopmod"}, {0x0295, "glottalstopreversed"}, {0x02c1, "glottalstopreversedmod"}, {0x02e4, "glottalstopreversedsuperior"}, {0x02a1, "glottalstopstroke"}, {0x02a2, "glottalstopstrokereversed"}, {0x1e21, "gmacron"}, {0xff47, "gmonospace"}, {0x3054, "gohiragana"}, {0x30b4, "gokatakana"}, {0x24a2, "gparen"}, {0x33ac, "gpasquare"}, {0x2207, "gradient"}, {0x0060, "grave"}, {0x0316, "gravebelowcmb"}, {0x0300, "gravecmb"}, {0x0300, "gravecomb"}, {0x0953, "gravedeva"}, {0x02ce, "gravelowmod"}, {0xff40, "gravemonospace"}, {0x0340, "gravetonecmb"}, {0x003e, "greater"}, {0x2265, "greaterequal"}, {0x22db, "greaterequalorless"}, {0xff1e, "greatermonospace"}, {0x2273, "greaterorequivalent"}, {0x2277, "greaterorless"}, {0x2267, "greateroverequal"}, {0xfe65, "greatersmall"}, {0x0261, "gscript"}, {0x01e5, "gstroke"}, {0x3050, "guhiragana"}, {0x00ab, "guillemotleft"}, {0x00bb, "guillemotright"}, {0x2039, "guilsinglleft"}, {0x203a, "guilsinglright"}, {0x30b0, "gukatakana"}, {0x3318, "guramusquare"}, {0x33c9, "gysquare"}, {0x0068, "h"}, {0x04a9, "haabkhasiancyrillic"}, {0x06c1, "haaltonearabic"}, {0x09b9, "habengali"}, {0x04b3, "hadescendercyrillic"}, {0x0939, "hadeva"}, {0x0ab9, "hagujarati"}, {0x0a39, "hagurmukhi"}, {0x062d, "haharabic"}, {0xfea2, "hahfinalarabic"}, {0xfea3, "hahinitialarabic"}, {0x306f, "hahiragana"}, {0xfea4, "hahmedialarabic"}, {0x332a, "haitusquare"}, {0x30cf, "hakatakana"}, {0xff8a, "hakatakanahalfwidth"}, {0x0a4d, "halantgurmukhi"}, {0x0621, "hamzaarabic"}, {0x0621, "hamzalowarabic"}, {0x3164, "hangulfiller"}, {0x044a, "hardsigncyrillic"}, {0x21bc, "harpoonleftbarbup"}, {0x21c0, "harpoonrightbarbup"}, {0x33ca, "hasquare"}, {0x05b2, "hatafpatah"}, {0x05b2, "hatafpatah16"}, {0x05b2, "hatafpatah23"}, {0x05b2, "hatafpatah2f"}, {0x05b2, "hatafpatahhebrew"}, {0x05b2, "hatafpatahnarrowhebrew"}, {0x05b2, "hatafpatahquarterhebrew"}, {0x05b2, "hatafpatahwidehebrew"}, {0x05b3, "hatafqamats"}, {0x05b3, "hatafqamats1b"}, {0x05b3, "hatafqamats28"}, {0x05b3, "hatafqamats34"}, {0x05b3, "hatafqamatshebrew"}, {0x05b3, "hatafqamatsnarrowhebrew"}, {0x05b3, "hatafqamatsquarterhebrew"}, {0x05b3, "hatafqamatswidehebrew"}, {0x05b1, "hatafsegol"}, {0x05b1, "hatafsegol17"}, {0x05b1, "hatafsegol24"}, {0x05b1, "hatafsegol30"}, {0x05b1, "hatafsegolhebrew"}, {0x05b1, "hatafsegolnarrowhebrew"}, {0x05b1, "hatafsegolquarterhebrew"}, {0x05b1, "hatafsegolwidehebrew"}, {0x0127, "hbar"}, {0x310f, "hbopomofo"}, {0x1e2b, "hbrevebelow"}, {0x1e29, "hcedilla"}, {0x24d7, "hcircle"}, {0x0125, "hcircumflex"}, {0x1e27, "hdieresis"}, {0x1e23, "hdotaccent"}, {0x1e25, "hdotbelow"}, {0x05d4, "he"}, {0x2665, "heart"}, {0x2665, "heartsuitblack"}, {0x2661, "heartsuitwhite"}, {0xfb34, "hedagesh"}, {0xfb34, "hedageshhebrew"}, {0x06c1, "hehaltonearabic"}, {0x0647, "heharabic"}, {0x05d4, "hehebrew"}, {0xfba7, "hehfinalaltonearabic"}, {0xfeea, "hehfinalalttwoarabic"}, {0xfeea, "hehfinalarabic"}, {0xfba5, "hehhamzaabovefinalarabic"}, {0xfba4, "hehhamzaaboveisolatedarabic"}, {0xfba8, "hehinitialaltonearabic"}, {0xfeeb, "hehinitialarabic"}, {0x3078, "hehiragana"}, {0xfba9, "hehmedialaltonearabic"}, {0xfeec, "hehmedialarabic"}, {0x337b, "heiseierasquare"}, {0x30d8, "hekatakana"}, {0xff8d, "hekatakanahalfwidth"}, {0x3336, "hekutaarusquare"}, {0x0267, "henghook"}, {0x3339, "herutusquare"}, {0x05d7, "het"}, {0x05d7, "hethebrew"}, {0x0266, "hhook"}, {0x02b1, "hhooksuperior"}, {0x327b, "hieuhacirclekorean"}, {0x321b, "hieuhaparenkorean"}, {0x326d, "hieuhcirclekorean"}, {0x314e, "hieuhkorean"}, {0x320d, "hieuhparenkorean"}, {0x3072, "hihiragana"}, {0x30d2, "hikatakana"}, {0xff8b, "hikatakanahalfwidth"}, {0x05b4, "hiriq"}, {0x05b4, "hiriq14"}, {0x05b4, "hiriq21"}, {0x05b4, "hiriq2d"}, {0x05b4, "hiriqhebrew"}, {0x05b4, "hiriqnarrowhebrew"}, {0x05b4, "hiriqquarterhebrew"}, {0x05b4, "hiriqwidehebrew"}, {0x1e96, "hlinebelow"}, {0xff48, "hmonospace"}, {0x0570, "hoarmenian"}, {0x0e2b, "hohipthai"}, {0x307b, "hohiragana"}, {0x30db, "hokatakana"}, {0xff8e, "hokatakanahalfwidth"}, {0x05b9, "holam"}, {0x05b9, "holam19"}, {0x05b9, "holam26"}, {0x05b9, "holam32"}, {0x05b9, "holamhebrew"}, {0x05b9, "holamnarrowhebrew"}, {0x05b9, "holamquarterhebrew"}, {0x05b9, "holamwidehebrew"}, {0x0e2e, "honokhukthai"}, {0x0309, "hookabovecomb"}, {0x0309, "hookcmb"}, {0x0321, "hookpalatalizedbelowcmb"}, {0x0322, "hookretroflexbelowcmb"}, {0x3342, "hoonsquare"}, {0x03e9, "horicoptic"}, {0x2015, "horizontalbar"}, {0x031b, "horncmb"}, {0x2668, "hotsprings"}, {0x2302, "house"}, {0x24a3, "hparen"}, {0x02b0, "hsuperior"}, {0x0265, "hturned"}, {0x3075, "huhiragana"}, {0x3333, "huiitosquare"}, {0x30d5, "hukatakana"}, {0xff8c, "hukatakanahalfwidth"}, {0x02dd, "hungarumlaut"}, {0x030b, "hungarumlautcmb"}, {0x0195, "hv"}, {0x002d, "hyphen"}, {0xf6e5, "hypheninferior"}, {0xff0d, "hyphenmonospace"}, {0xfe63, "hyphensmall"}, {0xf6e6, "hyphensuperior"}, {0x2010, "hyphentwo"}, {0x0069, "i"}, {0x00ed, "iacute"}, {0x044f, "iacyrillic"}, {0x0987, "ibengali"}, {0x3127, "ibopomofo"}, {0x012d, "ibreve"}, {0x01d0, "icaron"}, {0x24d8, "icircle"}, {0x00ee, "icircumflex"}, {0x0456, "icyrillic"}, {0x0209, "idblgrave"}, {0x328f, "ideographearthcircle"}, {0x328b, "ideographfirecircle"}, {0x323f, "ideographicallianceparen"}, {0x323a, "ideographiccallparen"}, {0x32a5, "ideographiccentrecircle"}, {0x3006, "ideographicclose"}, {0x3001, "ideographiccomma"}, {0xff64, "ideographiccommaleft"}, {0x3237, "ideographiccongratulationparen"}, {0x32a3, "ideographiccorrectcircle"}, {0x322f, "ideographicearthparen"}, {0x323d, "ideographicenterpriseparen"}, {0x329d, "ideographicexcellentcircle"}, {0x3240, "ideographicfestivalparen"}, {0x3296, "ideographicfinancialcircle"}, {0x3236, "ideographicfinancialparen"}, {0x322b, "ideographicfireparen"}, {0x3232, "ideographichaveparen"}, {0x32a4, "ideographichighcircle"}, {0x3005, "ideographiciterationmark"}, {0x3298, "ideographiclaborcircle"}, {0x3238, "ideographiclaborparen"}, {0x32a7, "ideographicleftcircle"}, {0x32a6, "ideographiclowcircle"}, {0x32a9, "ideographicmedicinecircle"}, {0x322e, "ideographicmetalparen"}, {0x322a, "ideographicmoonparen"}, {0x3234, "ideographicnameparen"}, {0x3002, "ideographicperiod"}, {0x329e, "ideographicprintcircle"}, {0x3243, "ideographicreachparen"}, {0x3239, "ideographicrepresentparen"}, {0x323e, "ideographicresourceparen"}, {0x32a8, "ideographicrightcircle"}, {0x3299, "ideographicsecretcircle"}, {0x3242, "ideographicselfparen"}, {0x3233, "ideographicsocietyparen"}, {0x3000, "ideographicspace"}, {0x3235, "ideographicspecialparen"}, {0x3231, "ideographicstockparen"}, {0x323b, "ideographicstudyparen"}, {0x3230, "ideographicsunparen"}, {0x323c, "ideographicsuperviseparen"}, {0x322c, "ideographicwaterparen"}, {0x322d, "ideographicwoodparen"}, {0x3007, "ideographiczero"}, {0x328e, "ideographmetalcircle"}, {0x328a, "ideographmooncircle"}, {0x3294, "ideographnamecircle"}, {0x3290, "ideographsuncircle"}, {0x328c, "ideographwatercircle"}, {0x328d, "ideographwoodcircle"}, {0x0907, "ideva"}, {0x00ef, "idieresis"}, {0x1e2f, "idieresisacute"}, {0x04e5, "idieresiscyrillic"}, {0x1ecb, "idotbelow"}, {0x04d7, "iebrevecyrillic"}, {0x0435, "iecyrillic"}, {0x3275, "ieungacirclekorean"}, {0x3215, "ieungaparenkorean"}, {0x3267, "ieungcirclekorean"}, {0x3147, "ieungkorean"}, {0x3207, "ieungparenkorean"}, {0x00ec, "igrave"}, {0x0a87, "igujarati"}, {0x0a07, "igurmukhi"}, {0x3044, "ihiragana"}, {0x1ec9, "ihookabove"}, {0x0988, "iibengali"}, {0x0438, "iicyrillic"}, {0x0908, "iideva"}, {0x0a88, "iigujarati"}, {0x0a08, "iigurmukhi"}, {0x0a40, "iimatragurmukhi"}, {0x020b, "iinvertedbreve"}, {0x0439, "iishortcyrillic"}, {0x09c0, "iivowelsignbengali"}, {0x0940, "iivowelsigndeva"}, {0x0ac0, "iivowelsigngujarati"}, {0x0133, "ij"}, {0x30a4, "ikatakana"}, {0xff72, "ikatakanahalfwidth"}, {0x3163, "ikorean"}, {0x02dc, "ilde"}, {0x05ac, "iluyhebrew"}, {0x012b, "imacron"}, {0x04e3, "imacroncyrillic"}, {0x2253, "imageorapproximatelyequal"}, {0x0a3f, "imatragurmukhi"}, {0xff49, "imonospace"}, {0x2206, "increment"}, {0x221e, "infinity"}, {0x056b, "iniarmenian"}, {0x222b, "integral"}, {0x2321, "integralbottom"}, {0x2321, "integralbt"}, {0xf8f5, "integralex"}, {0x2320, "integraltop"}, {0x2320, "integraltp"}, {0x2229, "intersection"}, {0x3305, "intisquare"}, {0x25d8, "invbullet"}, {0x25d9, "invcircle"}, {0x263b, "invsmileface"}, {0x0451, "iocyrillic"}, {0x012f, "iogonek"}, {0x03b9, "iota"}, {0x03ca, "iotadieresis"}, {0x0390, "iotadieresistonos"}, {0x0269, "iotalatin"}, {0x03af, "iotatonos"}, {0x24a4, "iparen"}, {0x0a72, "irigurmukhi"}, {0x3043, "ismallhiragana"}, {0x30a3, "ismallkatakana"}, {0xff68, "ismallkatakanahalfwidth"}, {0x09fa, "issharbengali"}, {0x0268, "istroke"}, {0xf6ed, "isuperior"}, {0x309d, "iterationhiragana"}, {0x30fd, "iterationkatakana"}, {0x0129, "itilde"}, {0x1e2d, "itildebelow"}, {0x3129, "iubopomofo"}, {0x044e, "iucyrillic"}, {0x09bf, "ivowelsignbengali"}, {0x093f, "ivowelsigndeva"}, {0x0abf, "ivowelsigngujarati"}, {0x0475, "izhitsacyrillic"}, {0x0477, "izhitsadblgravecyrillic"}, {0x006a, "j"}, {0x0571, "jaarmenian"}, {0x099c, "jabengali"}, {0x091c, "jadeva"}, {0x0a9c, "jagujarati"}, {0x0a1c, "jagurmukhi"}, {0x3110, "jbopomofo"}, {0x01f0, "jcaron"}, {0x24d9, "jcircle"}, {0x0135, "jcircumflex"}, {0x029d, "jcrossedtail"}, {0x025f, "jdotlessstroke"}, {0x0458, "jecyrillic"}, {0x062c, "jeemarabic"}, {0xfe9e, "jeemfinalarabic"}, {0xfe9f, "jeeminitialarabic"}, {0xfea0, "jeemmedialarabic"}, {0x0698, "jeharabic"}, {0xfb8b, "jehfinalarabic"}, {0x099d, "jhabengali"}, {0x091d, "jhadeva"}, {0x0a9d, "jhagujarati"}, {0x0a1d, "jhagurmukhi"}, {0x057b, "jheharmenian"}, {0x3004, "jis"}, {0xff4a, "jmonospace"}, {0x24a5, "jparen"}, {0x02b2, "jsuperior"}, {0x006b, "k"}, {0x04a1, "kabashkircyrillic"}, {0x0995, "kabengali"}, {0x1e31, "kacute"}, {0x043a, "kacyrillic"}, {0x049b, "kadescendercyrillic"}, {0x0915, "kadeva"}, {0x05db, "kaf"}, {0x0643, "kafarabic"}, {0xfb3b, "kafdagesh"}, {0xfb3b, "kafdageshhebrew"}, {0xfeda, "kaffinalarabic"}, {0x05db, "kafhebrew"}, {0xfedb, "kafinitialarabic"}, {0xfedc, "kafmedialarabic"}, {0xfb4d, "kafrafehebrew"}, {0x0a95, "kagujarati"}, {0x0a15, "kagurmukhi"}, {0x304b, "kahiragana"}, {0x04c4, "kahookcyrillic"}, {0x30ab, "kakatakana"}, {0xff76, "kakatakanahalfwidth"}, {0x03ba, "kappa"}, {0x03f0, "kappasymbolgreek"}, {0x3171, "kapyeounmieumkorean"}, {0x3184, "kapyeounphieuphkorean"}, {0x3178, "kapyeounpieupkorean"}, {0x3179, "kapyeounssangpieupkorean"}, {0x330d, "karoriisquare"}, {0x0640, "kashidaautoarabic"}, {0x0640, "kashidaautonosidebearingarabic"}, {0x30f5, "kasmallkatakana"}, {0x3384, "kasquare"}, {0x0650, "kasraarabic"}, {0x064d, "kasratanarabic"}, {0x049f, "kastrokecyrillic"}, {0xff70, "katahiraprolongmarkhalfwidth"}, {0x049d, "kaverticalstrokecyrillic"}, {0x310e, "kbopomofo"}, {0x3389, "kcalsquare"}, {0x01e9, "kcaron"}, {0x0137, "kcedilla"}, {0x24da, "kcircle"}, {0x0137, "kcommaaccent"}, {0x1e33, "kdotbelow"}, {0x0584, "keharmenian"}, {0x3051, "kehiragana"}, {0x30b1, "kekatakana"}, {0xff79, "kekatakanahalfwidth"}, {0x056f, "kenarmenian"}, {0x30f6, "kesmallkatakana"}, {0x0138, "kgreenlandic"}, {0x0996, "khabengali"}, {0x0445, "khacyrillic"}, {0x0916, "khadeva"}, {0x0a96, "khagujarati"}, {0x0a16, "khagurmukhi"}, {0x062e, "khaharabic"}, {0xfea6, "khahfinalarabic"}, {0xfea7, "khahinitialarabic"}, {0xfea8, "khahmedialarabic"}, {0x03e7, "kheicoptic"}, {0x0959, "khhadeva"}, {0x0a59, "khhagurmukhi"}, {0x3278, "khieukhacirclekorean"}, {0x3218, "khieukhaparenkorean"}, {0x326a, "khieukhcirclekorean"}, {0x314b, "khieukhkorean"}, {0x320a, "khieukhparenkorean"}, {0x0e02, "khokhaithai"}, {0x0e05, "khokhonthai"}, {0x0e03, "khokhuatthai"}, {0x0e04, "khokhwaithai"}, {0x0e5b, "khomutthai"}, {0x0199, "khook"}, {0x0e06, "khorakhangthai"}, {0x3391, "khzsquare"}, {0x304d, "kihiragana"}, {0x30ad, "kikatakana"}, {0xff77, "kikatakanahalfwidth"}, {0x3315, "kiroguramusquare"}, {0x3316, "kiromeetorusquare"}, {0x3314, "kirosquare"}, {0x326e, "kiyeokacirclekorean"}, {0x320e, "kiyeokaparenkorean"}, {0x3260, "kiyeokcirclekorean"}, {0x3131, "kiyeokkorean"}, {0x3200, "kiyeokparenkorean"}, {0x3133, "kiyeoksioskorean"}, {0x045c, "kjecyrillic"}, {0x1e35, "klinebelow"}, {0x3398, "klsquare"}, {0x33a6, "kmcubedsquare"}, {0xff4b, "kmonospace"}, {0x33a2, "kmsquaredsquare"}, {0x3053, "kohiragana"}, {0x33c0, "kohmsquare"}, {0x0e01, "kokaithai"}, {0x30b3, "kokatakana"}, {0xff7a, "kokatakanahalfwidth"}, {0x331e, "kooposquare"}, {0x0481, "koppacyrillic"}, {0x327f, "koreanstandardsymbol"}, {0x0343, "koroniscmb"}, {0x24a6, "kparen"}, {0x33aa, "kpasquare"}, {0x046f, "ksicyrillic"}, {0x33cf, "ktsquare"}, {0x029e, "kturned"}, {0x304f, "kuhiragana"}, {0x30af, "kukatakana"}, {0xff78, "kukatakanahalfwidth"}, {0x33b8, "kvsquare"}, {0x33be, "kwsquare"}, {0x006c, "l"}, {0x09b2, "labengali"}, {0x013a, "lacute"}, {0x0932, "ladeva"}, {0x0ab2, "lagujarati"}, {0x0a32, "lagurmukhi"}, {0x0e45, "lakkhangyaothai"}, {0xfefc, "lamaleffinalarabic"}, {0xfef8, "lamalefhamzaabovefinalarabic"}, {0xfef7, "lamalefhamzaaboveisolatedarabic"}, {0xfefa, "lamalefhamzabelowfinalarabic"}, {0xfef9, "lamalefhamzabelowisolatedarabic"}, {0xfefb, "lamalefisolatedarabic"}, {0xfef6, "lamalefmaddaabovefinalarabic"}, {0xfef5, "lamalefmaddaaboveisolatedarabic"}, {0x0644, "lamarabic"}, {0x03bb, "lambda"}, {0x019b, "lambdastroke"}, {0x05dc, "lamed"}, {0xfb3c, "lameddagesh"}, {0xfb3c, "lameddageshhebrew"}, {0x05dc, "lamedhebrew"}, {0xfede, "lamfinalarabic"}, {0xfcca, "lamhahinitialarabic"}, {0xfedf, "laminitialarabic"}, {0xfcc9, "lamjeeminitialarabic"}, {0xfccb, "lamkhahinitialarabic"}, {0xfdf2, "lamlamhehisolatedarabic"}, {0xfee0, "lammedialarabic"}, {0xfd88, "lammeemhahinitialarabic"}, {0xfccc, "lammeeminitialarabic"}, {0x25ef, "largecircle"}, {0x019a, "lbar"}, {0x026c, "lbelt"}, {0x310c, "lbopomofo"}, {0x013e, "lcaron"}, {0x013c, "lcedilla"}, {0x24db, "lcircle"}, {0x1e3d, "lcircumflexbelow"}, {0x013c, "lcommaaccent"}, {0x0140, "ldot"}, {0x0140, "ldotaccent"}, {0x1e37, "ldotbelow"}, {0x1e39, "ldotbelowmacron"}, {0x031a, "leftangleabovecmb"}, {0x0318, "lefttackbelowcmb"}, {0x003c, "less"}, {0x2264, "lessequal"}, {0x22da, "lessequalorgreater"}, {0xff1c, "lessmonospace"}, {0x2272, "lessorequivalent"}, {0x2276, "lessorgreater"}, {0x2266, "lessoverequal"}, {0xfe64, "lesssmall"}, {0x026e, "lezh"}, {0x258c, "lfblock"}, {0x026d, "lhookretroflex"}, {0x20a4, "lira"}, {0x056c, "liwnarmenian"}, {0x01c9, "lj"}, {0x0459, "ljecyrillic"}, {0xf6c0, "ll"}, {0x0933, "lladeva"}, {0x0ab3, "llagujarati"}, {0x1e3b, "llinebelow"}, {0x0934, "llladeva"}, {0x09e1, "llvocalicbengali"}, {0x0961, "llvocalicdeva"}, {0x09e3, "llvocalicvowelsignbengali"}, {0x0963, "llvocalicvowelsigndeva"}, {0x026b, "lmiddletilde"}, {0xff4c, "lmonospace"}, {0x33d0, "lmsquare"}, {0x0e2c, "lochulathai"}, {0x2227, "logicaland"}, {0x00ac, "logicalnot"}, {0x2310, "logicalnotreversed"}, {0x2228, "logicalor"}, {0x0e25, "lolingthai"}, {0x017f, "longs"}, {0xfe4e, "lowlinecenterline"}, {0x0332, "lowlinecmb"}, {0xfe4d, "lowlinedashed"}, {0x25ca, "lozenge"}, {0x24a7, "lparen"}, {0x0142, "lslash"}, {0x2113, "lsquare"}, {0xf6ee, "lsuperior"}, {0x2591, "ltshade"}, {0x0e26, "luthai"}, {0x098c, "lvocalicbengali"}, {0x090c, "lvocalicdeva"}, {0x09e2, "lvocalicvowelsignbengali"}, {0x0962, "lvocalicvowelsigndeva"}, {0x33d3, "lxsquare"}, {0x006d, "m"}, {0x09ae, "mabengali"}, {0x00af, "macron"}, {0x0331, "macronbelowcmb"}, {0x0304, "macroncmb"}, {0x02cd, "macronlowmod"}, {0xffe3, "macronmonospace"}, {0x1e3f, "macute"}, {0x092e, "madeva"}, {0x0aae, "magujarati"}, {0x0a2e, "magurmukhi"}, {0x05a4, "mahapakhhebrew"}, {0x05a4, "mahapakhlefthebrew"}, {0x307e, "mahiragana"}, {0xf895, "maichattawalowleftthai"}, {0xf894, "maichattawalowrightthai"}, {0x0e4b, "maichattawathai"}, {0xf893, "maichattawaupperleftthai"}, {0xf88c, "maieklowleftthai"}, {0xf88b, "maieklowrightthai"}, {0x0e48, "maiekthai"}, {0xf88a, "maiekupperleftthai"}, {0xf884, "maihanakatleftthai"}, {0x0e31, "maihanakatthai"}, {0xf889, "maitaikhuleftthai"}, {0x0e47, "maitaikhuthai"}, {0xf88f, "maitholowleftthai"}, {0xf88e, "maitholowrightthai"}, {0x0e49, "maithothai"}, {0xf88d, "maithoupperleftthai"}, {0xf892, "maitrilowleftthai"}, {0xf891, "maitrilowrightthai"}, {0x0e4a, "maitrithai"}, {0xf890, "maitriupperleftthai"}, {0x0e46, "maiyamokthai"}, {0x30de, "makatakana"}, {0xff8f, "makatakanahalfwidth"}, {0x2642, "male"}, {0x3347, "mansyonsquare"}, {0x05be, "maqafhebrew"}, {0x2642, "mars"}, {0x05af, "masoracirclehebrew"}, {0x3383, "masquare"}, {0x3107, "mbopomofo"}, {0x33d4, "mbsquare"}, {0x24dc, "mcircle"}, {0x33a5, "mcubedsquare"}, {0x1e41, "mdotaccent"}, {0x1e43, "mdotbelow"}, {0x0645, "meemarabic"}, {0xfee2, "meemfinalarabic"}, {0xfee3, "meeminitialarabic"}, {0xfee4, "meemmedialarabic"}, {0xfcd1, "meemmeeminitialarabic"}, {0xfc48, "meemmeemisolatedarabic"}, {0x334d, "meetorusquare"}, {0x3081, "mehiragana"}, {0x337e, "meizierasquare"}, {0x30e1, "mekatakana"}, {0xff92, "mekatakanahalfwidth"}, {0x05de, "mem"}, {0xfb3e, "memdagesh"}, {0xfb3e, "memdageshhebrew"}, {0x05de, "memhebrew"}, {0x0574, "menarmenian"}, {0x05a5, "merkhahebrew"}, {0x05a6, "merkhakefulahebrew"}, {0x05a6, "merkhakefulalefthebrew"}, {0x05a5, "merkhalefthebrew"}, {0x0271, "mhook"}, {0x3392, "mhzsquare"}, {0xff65, "middledotkatakanahalfwidth"}, {0x00b7, "middot"}, {0x3272, "mieumacirclekorean"}, {0x3212, "mieumaparenkorean"}, {0x3264, "mieumcirclekorean"}, {0x3141, "mieumkorean"}, {0x3170, "mieumpansioskorean"}, {0x3204, "mieumparenkorean"}, {0x316e, "mieumpieupkorean"}, {0x316f, "mieumsioskorean"}, {0x307f, "mihiragana"}, {0x30df, "mikatakana"}, {0xff90, "mikatakanahalfwidth"}, {0x2212, "minus"}, {0x0320, "minusbelowcmb"}, {0x2296, "minuscircle"}, {0x02d7, "minusmod"}, {0x2213, "minusplus"}, {0x2032, "minute"}, {0x334a, "miribaarusquare"}, {0x3349, "mirisquare"}, {0x0270, "mlonglegturned"}, {0x3396, "mlsquare"}, {0x33a3, "mmcubedsquare"}, {0xff4d, "mmonospace"}, {0x339f, "mmsquaredsquare"}, {0x3082, "mohiragana"}, {0x33c1, "mohmsquare"}, {0x30e2, "mokatakana"}, {0xff93, "mokatakanahalfwidth"}, {0x33d6, "molsquare"}, {0x0e21, "momathai"}, {0x33a7, "moverssquare"}, {0x33a8, "moverssquaredsquare"}, {0x24a8, "mparen"}, {0x33ab, "mpasquare"}, {0x33b3, "mssquare"}, {0xf6ef, "msuperior"}, {0x026f, "mturned"}, {0x00b5, "mu"}, {0x00b5, "mu1"}, {0x3382, "muasquare"}, {0x226b, "muchgreater"}, {0x226a, "muchless"}, {0x338c, "mufsquare"}, {0x03bc, "mugreek"}, {0x338d, "mugsquare"}, {0x3080, "muhiragana"}, {0x30e0, "mukatakana"}, {0xff91, "mukatakanahalfwidth"}, {0x3395, "mulsquare"}, {0x00d7, "multiply"}, {0x339b, "mumsquare"}, {0x05a3, "munahhebrew"}, {0x05a3, "munahlefthebrew"}, {0x266a, "musicalnote"}, {0x266b, "musicalnotedbl"}, {0x266d, "musicflatsign"}, {0x266f, "musicsharpsign"}, {0x33b2, "mussquare"}, {0x33b6, "muvsquare"}, {0x33bc, "muwsquare"}, {0x33b9, "mvmegasquare"}, {0x33b7, "mvsquare"}, {0x33bf, "mwmegasquare"}, {0x33bd, "mwsquare"}, {0x006e, "n"}, {0x09a8, "nabengali"}, {0x2207, "nabla"}, {0x0144, "nacute"}, {0x0928, "nadeva"}, {0x0aa8, "nagujarati"}, {0x0a28, "nagurmukhi"}, {0x306a, "nahiragana"}, {0x30ca, "nakatakana"}, {0xff85, "nakatakanahalfwidth"}, {0x0149, "napostrophe"}, {0x3381, "nasquare"}, {0x310b, "nbopomofo"}, {0x00a0, "nbspace"}, {0x0148, "ncaron"}, {0x0146, "ncedilla"}, {0x24dd, "ncircle"}, {0x1e4b, "ncircumflexbelow"}, {0x0146, "ncommaaccent"}, {0x1e45, "ndotaccent"}, {0x1e47, "ndotbelow"}, {0x306d, "nehiragana"}, {0x30cd, "nekatakana"}, {0xff88, "nekatakanahalfwidth"}, {0x20aa, "newsheqelsign"}, {0x338b, "nfsquare"}, {0x0999, "ngabengali"}, {0x0919, "ngadeva"}, {0x0a99, "ngagujarati"}, {0x0a19, "ngagurmukhi"}, {0x0e07, "ngonguthai"}, {0x3093, "nhiragana"}, {0x0272, "nhookleft"}, {0x0273, "nhookretroflex"}, {0x326f, "nieunacirclekorean"}, {0x320f, "nieunaparenkorean"}, {0x3135, "nieuncieuckorean"}, {0x3261, "nieuncirclekorean"}, {0x3136, "nieunhieuhkorean"}, {0x3134, "nieunkorean"}, {0x3168, "nieunpansioskorean"}, {0x3201, "nieunparenkorean"}, {0x3167, "nieunsioskorean"}, {0x3166, "nieuntikeutkorean"}, {0x306b, "nihiragana"}, {0x30cb, "nikatakana"}, {0xff86, "nikatakanahalfwidth"}, {0xf899, "nikhahitleftthai"}, {0x0e4d, "nikhahitthai"}, {0x0039, "nine"}, {0x0669, "ninearabic"}, {0x09ef, "ninebengali"}, {0x2468, "ninecircle"}, {0x2792, "ninecircleinversesansserif"}, {0x096f, "ninedeva"}, {0x0aef, "ninegujarati"}, {0x0a6f, "ninegurmukhi"}, {0x0669, "ninehackarabic"}, {0x3029, "ninehangzhou"}, {0x3228, "nineideographicparen"}, {0x2089, "nineinferior"}, {0xff19, "ninemonospace"}, {0xf739, "nineoldstyle"}, {0x247c, "nineparen"}, {0x2490, "nineperiod"}, {0x06f9, "ninepersian"}, {0x2178, "nineroman"}, {0x2079, "ninesuperior"}, {0x2472, "nineteencircle"}, {0x2486, "nineteenparen"}, {0x249a, "nineteenperiod"}, {0x0e59, "ninethai"}, {0x01cc, "nj"}, {0x045a, "njecyrillic"}, {0x30f3, "nkatakana"}, {0xff9d, "nkatakanahalfwidth"}, {0x019e, "nlegrightlong"}, {0x1e49, "nlinebelow"}, {0xff4e, "nmonospace"}, {0x339a, "nmsquare"}, {0x09a3, "nnabengali"}, {0x0923, "nnadeva"}, {0x0aa3, "nnagujarati"}, {0x0a23, "nnagurmukhi"}, {0x0929, "nnnadeva"}, {0x306e, "nohiragana"}, {0x30ce, "nokatakana"}, {0xff89, "nokatakanahalfwidth"}, {0x00a0, "nonbreakingspace"}, {0x0e13, "nonenthai"}, {0x0e19, "nonuthai"}, {0x0646, "noonarabic"}, {0xfee6, "noonfinalarabic"}, {0x06ba, "noonghunnaarabic"}, {0xfb9f, "noonghunnafinalarabic"}, {0xfee7, "nooninitialarabic"}, {0xfcd2, "noonjeeminitialarabic"}, {0xfc4b, "noonjeemisolatedarabic"}, {0xfee8, "noonmedialarabic"}, {0xfcd5, "noonmeeminitialarabic"}, {0xfc4e, "noonmeemisolatedarabic"}, {0xfc8d, "noonnoonfinalarabic"}, {0x220c, "notcontains"}, {0x2209, "notelement"}, {0x2209, "notelementof"}, {0x2260, "notequal"}, {0x226f, "notgreater"}, {0x2271, "notgreaternorequal"}, {0x2279, "notgreaternorless"}, {0x2262, "notidentical"}, {0x226e, "notless"}, {0x2270, "notlessnorequal"}, {0x2226, "notparallel"}, {0x2280, "notprecedes"}, {0x2284, "notsubset"}, {0x2281, "notsucceeds"}, {0x2285, "notsuperset"}, {0x0576, "nowarmenian"}, {0x24a9, "nparen"}, {0x33b1, "nssquare"}, {0x207f, "nsuperior"}, {0x00f1, "ntilde"}, {0x03bd, "nu"}, {0x306c, "nuhiragana"}, {0x30cc, "nukatakana"}, {0xff87, "nukatakanahalfwidth"}, {0x09bc, "nuktabengali"}, {0x093c, "nuktadeva"}, {0x0abc, "nuktagujarati"}, {0x0a3c, "nuktagurmukhi"}, {0x0023, "numbersign"}, {0xff03, "numbersignmonospace"}, {0xfe5f, "numbersignsmall"}, {0x0374, "numeralsigngreek"}, {0x0375, "numeralsignlowergreek"}, {0x2116, "numero"}, {0x05e0, "nun"}, {0xfb40, "nundagesh"}, {0xfb40, "nundageshhebrew"}, {0x05e0, "nunhebrew"}, {0x33b5, "nvsquare"}, {0x33bb, "nwsquare"}, {0x099e, "nyabengali"}, {0x091e, "nyadeva"}, {0x0a9e, "nyagujarati"}, {0x0a1e, "nyagurmukhi"}, {0x006f, "o"}, {0x00f3, "oacute"}, {0x0e2d, "oangthai"}, {0x0275, "obarred"}, {0x04e9, "obarredcyrillic"}, {0x04eb, "obarreddieresiscyrillic"}, {0x0993, "obengali"}, {0x311b, "obopomofo"}, {0x014f, "obreve"}, {0x0911, "ocandradeva"}, {0x0a91, "ocandragujarati"}, {0x0949, "ocandravowelsigndeva"}, {0x0ac9, "ocandravowelsigngujarati"}, {0x01d2, "ocaron"}, {0x24de, "ocircle"}, {0x00f4, "ocircumflex"}, {0x1ed1, "ocircumflexacute"}, {0x1ed9, "ocircumflexdotbelow"}, {0x1ed3, "ocircumflexgrave"}, {0x1ed5, "ocircumflexhookabove"}, {0x1ed7, "ocircumflextilde"}, {0x043e, "ocyrillic"}, {0x0151, "odblacute"}, {0x020d, "odblgrave"}, {0x0913, "odeva"}, {0x00f6, "odieresis"}, {0x04e7, "odieresiscyrillic"}, {0x1ecd, "odotbelow"}, {0x0153, "oe"}, {0x315a, "oekorean"}, {0x02db, "ogonek"}, {0x0328, "ogonekcmb"}, {0x00f2, "ograve"}, {0x0a93, "ogujarati"}, {0x0585, "oharmenian"}, {0x304a, "ohiragana"}, {0x1ecf, "ohookabove"}, {0x01a1, "ohorn"}, {0x1edb, "ohornacute"}, {0x1ee3, "ohorndotbelow"}, {0x1edd, "ohorngrave"}, {0x1edf, "ohornhookabove"}, {0x1ee1, "ohorntilde"}, {0x0151, "ohungarumlaut"}, {0x01a3, "oi"}, {0x020f, "oinvertedbreve"}, {0x30aa, "okatakana"}, {0xff75, "okatakanahalfwidth"}, {0x3157, "okorean"}, {0x05ab, "olehebrew"}, {0x014d, "omacron"}, {0x1e53, "omacronacute"}, {0x1e51, "omacrongrave"}, {0x0950, "omdeva"}, {0x03c9, "omega"}, {0x03d6, "omega1"}, {0x0461, "omegacyrillic"}, {0x0277, "omegalatinclosed"}, {0x047b, "omegaroundcyrillic"}, {0x047d, "omegatitlocyrillic"}, {0x03ce, "omegatonos"}, {0x0ad0, "omgujarati"}, {0x03bf, "omicron"}, {0x03cc, "omicrontonos"}, {0xff4f, "omonospace"}, {0x0031, "one"}, {0x0661, "onearabic"}, {0x09e7, "onebengali"}, {0x2460, "onecircle"}, {0x278a, "onecircleinversesansserif"}, {0x0967, "onedeva"}, {0x2024, "onedotenleader"}, {0x215b, "oneeighth"}, {0xf6dc, "onefitted"}, {0x0ae7, "onegujarati"}, {0x0a67, "onegurmukhi"}, {0x0661, "onehackarabic"}, {0x00bd, "onehalf"}, {0x3021, "onehangzhou"}, {0x3220, "oneideographicparen"}, {0x2081, "oneinferior"}, {0xff11, "onemonospace"}, {0x09f4, "onenumeratorbengali"}, {0xf731, "oneoldstyle"}, {0x2474, "oneparen"}, {0x2488, "oneperiod"}, {0x06f1, "onepersian"}, {0x00bc, "onequarter"}, {0x2170, "oneroman"}, {0x00b9, "onesuperior"}, {0x0e51, "onethai"}, {0x2153, "onethird"}, {0x01eb, "oogonek"}, {0x01ed, "oogonekmacron"}, {0x0a13, "oogurmukhi"}, {0x0a4b, "oomatragurmukhi"}, {0x0254, "oopen"}, {0x24aa, "oparen"}, {0x25e6, "openbullet"}, {0x2325, "option"}, {0x00aa, "ordfeminine"}, {0x00ba, "ordmasculine"}, {0x221f, "orthogonal"}, {0x0912, "oshortdeva"}, {0x094a, "oshortvowelsigndeva"}, {0x00f8, "oslash"}, {0x01ff, "oslashacute"}, {0x3049, "osmallhiragana"}, {0x30a9, "osmallkatakana"}, {0xff6b, "osmallkatakanahalfwidth"}, {0x01ff, "ostrokeacute"}, {0xf6f0, "osuperior"}, {0x047f, "otcyrillic"}, {0x00f5, "otilde"}, {0x1e4d, "otildeacute"}, {0x1e4f, "otildedieresis"}, {0x3121, "oubopomofo"}, {0x203e, "overline"}, {0xfe4a, "overlinecenterline"}, {0x0305, "overlinecmb"}, {0xfe49, "overlinedashed"}, {0xfe4c, "overlinedblwavy"}, {0xfe4b, "overlinewavy"}, {0x00af, "overscore"}, {0x09cb, "ovowelsignbengali"}, {0x094b, "ovowelsigndeva"}, {0x0acb, "ovowelsigngujarati"}, {0x0070, "p"}, {0x3380, "paampssquare"}, {0x332b, "paasentosquare"}, {0x09aa, "pabengali"}, {0x1e55, "pacute"}, {0x092a, "padeva"}, {0x21df, "pagedown"}, {0x21de, "pageup"}, {0x0aaa, "pagujarati"}, {0x0a2a, "pagurmukhi"}, {0x3071, "pahiragana"}, {0x0e2f, "paiyannoithai"}, {0x30d1, "pakatakana"}, {0x0484, "palatalizationcyrilliccmb"}, {0x04c0, "palochkacyrillic"}, {0x317f, "pansioskorean"}, {0x00b6, "paragraph"}, {0x2225, "parallel"}, {0x0028, "parenleft"}, {0xfd3e, "parenleftaltonearabic"}, {0xf8ed, "parenleftbt"}, {0xf8ec, "parenleftex"}, {0x208d, "parenleftinferior"}, {0xff08, "parenleftmonospace"}, {0xfe59, "parenleftsmall"}, {0x207d, "parenleftsuperior"}, {0xf8eb, "parenlefttp"}, {0xfe35, "parenleftvertical"}, {0x0029, "parenright"}, {0xfd3f, "parenrightaltonearabic"}, {0xf8f8, "parenrightbt"}, {0xf8f7, "parenrightex"}, {0x208e, "parenrightinferior"}, {0xff09, "parenrightmonospace"}, {0xfe5a, "parenrightsmall"}, {0x207e, "parenrightsuperior"}, {0xf8f6, "parenrighttp"}, {0xfe36, "parenrightvertical"}, {0x2202, "partialdiff"}, {0x05c0, "paseqhebrew"}, {0x0599, "pashtahebrew"}, {0x33a9, "pasquare"}, {0x05b7, "patah"}, {0x05b7, "patah11"}, {0x05b7, "patah1d"}, {0x05b7, "patah2a"}, {0x05b7, "patahhebrew"}, {0x05b7, "patahnarrowhebrew"}, {0x05b7, "patahquarterhebrew"}, {0x05b7, "patahwidehebrew"}, {0x05a1, "pazerhebrew"}, {0x3106, "pbopomofo"}, {0x24df, "pcircle"}, {0x1e57, "pdotaccent"}, {0x05e4, "pe"}, {0x043f, "pecyrillic"}, {0xfb44, "pedagesh"}, {0xfb44, "pedageshhebrew"}, {0x333b, "peezisquare"}, {0xfb43, "pefinaldageshhebrew"}, {0x067e, "peharabic"}, {0x057a, "peharmenian"}, {0x05e4, "pehebrew"}, {0xfb57, "pehfinalarabic"}, {0xfb58, "pehinitialarabic"}, {0x307a, "pehiragana"}, {0xfb59, "pehmedialarabic"}, {0x30da, "pekatakana"}, {0x04a7, "pemiddlehookcyrillic"}, {0xfb4e, "perafehebrew"}, {0x0025, "percent"}, {0x066a, "percentarabic"}, {0xff05, "percentmonospace"}, {0xfe6a, "percentsmall"}, {0x002e, "period"}, {0x0589, "periodarmenian"}, {0x00b7, "periodcentered"}, {0xff61, "periodhalfwidth"}, {0xf6e7, "periodinferior"}, {0xff0e, "periodmonospace"}, {0xfe52, "periodsmall"}, {0xf6e8, "periodsuperior"}, {0x0342, "perispomenigreekcmb"}, {0x22a5, "perpendicular"}, {0x2030, "perthousand"}, {0x20a7, "peseta"}, {0x338a, "pfsquare"}, {0x09ab, "phabengali"}, {0x092b, "phadeva"}, {0x0aab, "phagujarati"}, {0x0a2b, "phagurmukhi"}, {0x03c6, "phi"}, {0x03d5, "phi1"}, {0x327a, "phieuphacirclekorean"}, {0x321a, "phieuphaparenkorean"}, {0x326c, "phieuphcirclekorean"}, {0x314d, "phieuphkorean"}, {0x320c, "phieuphparenkorean"}, {0x0278, "philatin"}, {0x0e3a, "phinthuthai"}, {0x03d5, "phisymbolgreek"}, {0x01a5, "phook"}, {0x0e1e, "phophanthai"}, {0x0e1c, "phophungthai"}, {0x0e20, "phosamphaothai"}, {0x03c0, "pi"}, {0x3273, "pieupacirclekorean"}, {0x3213, "pieupaparenkorean"}, {0x3176, "pieupcieuckorean"}, {0x3265, "pieupcirclekorean"}, {0x3172, "pieupkiyeokkorean"}, {0x3142, "pieupkorean"}, {0x3205, "pieupparenkorean"}, {0x3174, "pieupsioskiyeokkorean"}, {0x3144, "pieupsioskorean"}, {0x3175, "pieupsiostikeutkorean"}, {0x3177, "pieupthieuthkorean"}, {0x3173, "pieuptikeutkorean"}, {0x3074, "pihiragana"}, {0x30d4, "pikatakana"}, {0x03d6, "pisymbolgreek"}, {0x0583, "piwrarmenian"}, {0x002b, "plus"}, {0x031f, "plusbelowcmb"}, {0x2295, "pluscircle"}, {0x00b1, "plusminus"}, {0x02d6, "plusmod"}, {0xff0b, "plusmonospace"}, {0xfe62, "plussmall"}, {0x207a, "plussuperior"}, {0xff50, "pmonospace"}, {0x33d8, "pmsquare"}, {0x307d, "pohiragana"}, {0x261f, "pointingindexdownwhite"}, {0x261c, "pointingindexleftwhite"}, {0x261e, "pointingindexrightwhite"}, {0x261d, "pointingindexupwhite"}, {0x30dd, "pokatakana"}, {0x0e1b, "poplathai"}, {0x3012, "postalmark"}, {0x3020, "postalmarkface"}, {0x24ab, "pparen"}, {0x227a, "precedes"}, {0x211e, "prescription"}, {0x02b9, "primemod"}, {0x2035, "primereversed"}, {0x220f, "product"}, {0x2305, "projective"}, {0x30fc, "prolongedkana"}, {0x2318, "propellor"}, {0x2282, "propersubset"}, {0x2283, "propersuperset"}, {0x2237, "proportion"}, {0x221d, "proportional"}, {0x03c8, "psi"}, {0x0471, "psicyrillic"}, {0x0486, "psilipneumatacyrilliccmb"}, {0x33b0, "pssquare"}, {0x3077, "puhiragana"}, {0x30d7, "pukatakana"}, {0x33b4, "pvsquare"}, {0x33ba, "pwsquare"}, {0x0071, "q"}, {0x0958, "qadeva"}, {0x05a8, "qadmahebrew"}, {0x0642, "qafarabic"}, {0xfed6, "qaffinalarabic"}, {0xfed7, "qafinitialarabic"}, {0xfed8, "qafmedialarabic"}, {0x05b8, "qamats"}, {0x05b8, "qamats10"}, {0x05b8, "qamats1a"}, {0x05b8, "qamats1c"}, {0x05b8, "qamats27"}, {0x05b8, "qamats29"}, {0x05b8, "qamats33"}, {0x05b8, "qamatsde"}, {0x05b8, "qamatshebrew"}, {0x05b8, "qamatsnarrowhebrew"}, {0x05b8, "qamatsqatanhebrew"}, {0x05b8, "qamatsqatannarrowhebrew"}, {0x05b8, "qamatsqatanquarterhebrew"}, {0x05b8, "qamatsqatanwidehebrew"}, {0x05b8, "qamatsquarterhebrew"}, {0x05b8, "qamatswidehebrew"}, {0x059f, "qarneyparahebrew"}, {0x3111, "qbopomofo"}, {0x24e0, "qcircle"}, {0x02a0, "qhook"}, {0xff51, "qmonospace"}, {0x05e7, "qof"}, {0xfb47, "qofdagesh"}, {0xfb47, "qofdageshhebrew"}, {0x05e7, "qofhebrew"}, {0x24ac, "qparen"}, {0x2669, "quarternote"}, {0x05bb, "qubuts"}, {0x05bb, "qubuts18"}, {0x05bb, "qubuts25"}, {0x05bb, "qubuts31"}, {0x05bb, "qubutshebrew"}, {0x05bb, "qubutsnarrowhebrew"}, {0x05bb, "qubutsquarterhebrew"}, {0x05bb, "qubutswidehebrew"}, {0x003f, "question"}, {0x061f, "questionarabic"}, {0x055e, "questionarmenian"}, {0x00bf, "questiondown"}, {0xf7bf, "questiondownsmall"}, {0x037e, "questiongreek"}, {0xff1f, "questionmonospace"}, {0xf73f, "questionsmall"}, {0x0022, "quotedbl"}, {0x201e, "quotedblbase"}, {0x201c, "quotedblleft"}, {0xff02, "quotedblmonospace"}, {0x301e, "quotedblprime"}, {0x301d, "quotedblprimereversed"}, {0x201d, "quotedblright"}, {0x2018, "quoteleft"}, {0x201b, "quoteleftreversed"}, {0x201b, "quotereversed"}, {0x2019, "quoteright"}, {0x0149, "quoterightn"}, {0x201a, "quotesinglbase"}, {0x0027, "quotesingle"}, {0xff07, "quotesinglemonospace"}, {0x0072, "r"}, {0x057c, "raarmenian"}, {0x09b0, "rabengali"}, {0x0155, "racute"}, {0x0930, "radeva"}, {0x221a, "radical"}, {0xf8e5, "radicalex"}, {0x33ae, "radoverssquare"}, {0x33af, "radoverssquaredsquare"}, {0x33ad, "radsquare"}, {0x05bf, "rafe"}, {0x05bf, "rafehebrew"}, {0x0ab0, "ragujarati"}, {0x0a30, "ragurmukhi"}, {0x3089, "rahiragana"}, {0x30e9, "rakatakana"}, {0xff97, "rakatakanahalfwidth"}, {0x09f1, "ralowerdiagonalbengali"}, {0x09f0, "ramiddlediagonalbengali"}, {0x0264, "ramshorn"}, {0x2236, "ratio"}, {0x3116, "rbopomofo"}, {0x0159, "rcaron"}, {0x0157, "rcedilla"}, {0x24e1, "rcircle"}, {0x0157, "rcommaaccent"}, {0x0211, "rdblgrave"}, {0x1e59, "rdotaccent"}, {0x1e5b, "rdotbelow"}, {0x1e5d, "rdotbelowmacron"}, {0x203b, "referencemark"}, {0x2286, "reflexsubset"}, {0x2287, "reflexsuperset"}, {0x00ae, "registered"}, {0x00ae, "registersans"}, {0x00ae, "registerserif"}, {0x0631, "reharabic"}, {0x0580, "reharmenian"}, {0xfeae, "rehfinalarabic"}, {0x308c, "rehiragana"}, {0x30ec, "rekatakana"}, {0xff9a, "rekatakanahalfwidth"}, {0x05e8, "resh"}, {0xfb48, "reshdageshhebrew"}, {0x05e8, "reshhebrew"}, {0x223d, "reversedtilde"}, {0x0597, "reviahebrew"}, {0x0597, "reviamugrashhebrew"}, {0x2310, "revlogicalnot"}, {0x027e, "rfishhook"}, {0x027f, "rfishhookreversed"}, {0x09dd, "rhabengali"}, {0x095d, "rhadeva"}, {0x03c1, "rho"}, {0x027d, "rhook"}, {0x027b, "rhookturned"}, {0x02b5, "rhookturnedsuperior"}, {0x03f1, "rhosymbolgreek"}, {0x02de, "rhotichookmod"}, {0x3271, "rieulacirclekorean"}, {0x3211, "rieulaparenkorean"}, {0x3263, "rieulcirclekorean"}, {0x3140, "rieulhieuhkorean"}, {0x313a, "rieulkiyeokkorean"}, {0x3169, "rieulkiyeoksioskorean"}, {0x3139, "rieulkorean"}, {0x313b, "rieulmieumkorean"}, {0x316c, "rieulpansioskorean"}, {0x3203, "rieulparenkorean"}, {0x313f, "rieulphieuphkorean"}, {0x313c, "rieulpieupkorean"}, {0x316b, "rieulpieupsioskorean"}, {0x313d, "rieulsioskorean"}, {0x313e, "rieulthieuthkorean"}, {0x316a, "rieultikeutkorean"}, {0x316d, "rieulyeorinhieuhkorean"}, {0x221f, "rightangle"}, {0x0319, "righttackbelowcmb"}, {0x22bf, "righttriangle"}, {0x308a, "rihiragana"}, {0x30ea, "rikatakana"}, {0xff98, "rikatakanahalfwidth"}, {0x02da, "ring"}, {0x0325, "ringbelowcmb"}, {0x030a, "ringcmb"}, {0x02bf, "ringhalfleft"}, {0x0559, "ringhalfleftarmenian"}, {0x031c, "ringhalfleftbelowcmb"}, {0x02d3, "ringhalfleftcentered"}, {0x02be, "ringhalfright"}, {0x0339, "ringhalfrightbelowcmb"}, {0x02d2, "ringhalfrightcentered"}, {0x0213, "rinvertedbreve"}, {0x3351, "rittorusquare"}, {0x1e5f, "rlinebelow"}, {0x027c, "rlongleg"}, {0x027a, "rlonglegturned"}, {0xff52, "rmonospace"}, {0x308d, "rohiragana"}, {0x30ed, "rokatakana"}, {0xff9b, "rokatakanahalfwidth"}, {0x0e23, "roruathai"}, {0x24ad, "rparen"}, {0x09dc, "rrabengali"}, {0x0931, "rradeva"}, {0x0a5c, "rragurmukhi"}, {0x0691, "rreharabic"}, {0xfb8d, "rrehfinalarabic"}, {0x09e0, "rrvocalicbengali"}, {0x0960, "rrvocalicdeva"}, {0x0ae0, "rrvocalicgujarati"}, {0x09c4, "rrvocalicvowelsignbengali"}, {0x0944, "rrvocalicvowelsigndeva"}, {0x0ac4, "rrvocalicvowelsigngujarati"}, {0xf6f1, "rsuperior"}, {0x2590, "rtblock"}, {0x0279, "rturned"}, {0x02b4, "rturnedsuperior"}, {0x308b, "ruhiragana"}, {0x30eb, "rukatakana"}, {0xff99, "rukatakanahalfwidth"}, {0x09f2, "rupeemarkbengali"}, {0x09f3, "rupeesignbengali"}, {0xf6dd, "rupiah"}, {0x0e24, "ruthai"}, {0x098b, "rvocalicbengali"}, {0x090b, "rvocalicdeva"}, {0x0a8b, "rvocalicgujarati"}, {0x09c3, "rvocalicvowelsignbengali"}, {0x0943, "rvocalicvowelsigndeva"}, {0x0ac3, "rvocalicvowelsigngujarati"}, {0x0073, "s"}, {0x09b8, "sabengali"}, {0x015b, "sacute"}, {0x1e65, "sacutedotaccent"}, {0x0635, "sadarabic"}, {0x0938, "sadeva"}, {0xfeba, "sadfinalarabic"}, {0xfebb, "sadinitialarabic"}, {0xfebc, "sadmedialarabic"}, {0x0ab8, "sagujarati"}, {0x0a38, "sagurmukhi"}, {0x3055, "sahiragana"}, {0x30b5, "sakatakana"}, {0xff7b, "sakatakanahalfwidth"}, {0xfdfa, "sallallahoualayhewasallamarabic"}, {0x05e1, "samekh"}, {0xfb41, "samekhdagesh"}, {0xfb41, "samekhdageshhebrew"}, {0x05e1, "samekhhebrew"}, {0x0e32, "saraaathai"}, {0x0e41, "saraaethai"}, {0x0e44, "saraaimaimalaithai"}, {0x0e43, "saraaimaimuanthai"}, {0x0e33, "saraamthai"}, {0x0e30, "saraathai"}, {0x0e40, "saraethai"}, {0xf886, "saraiileftthai"}, {0x0e35, "saraiithai"}, {0xf885, "saraileftthai"}, {0x0e34, "saraithai"}, {0x0e42, "saraothai"}, {0xf888, "saraueeleftthai"}, {0x0e37, "saraueethai"}, {0xf887, "saraueleftthai"}, {0x0e36, "sarauethai"}, {0x0e38, "sarauthai"}, {0x0e39, "sarauuthai"}, {0x3119, "sbopomofo"}, {0x0161, "scaron"}, {0x1e67, "scarondotaccent"}, {0x015f, "scedilla"}, {0x0259, "schwa"}, {0x04d9, "schwacyrillic"}, {0x04db, "schwadieresiscyrillic"}, {0x025a, "schwahook"}, {0x24e2, "scircle"}, {0x015d, "scircumflex"}, {0x0219, "scommaaccent"}, {0x1e61, "sdotaccent"}, {0x1e63, "sdotbelow"}, {0x1e69, "sdotbelowdotaccent"}, {0x033c, "seagullbelowcmb"}, {0x2033, "second"}, {0x02ca, "secondtonechinese"}, {0x00a7, "section"}, {0x0633, "seenarabic"}, {0xfeb2, "seenfinalarabic"}, {0xfeb3, "seeninitialarabic"}, {0xfeb4, "seenmedialarabic"}, {0x05b6, "segol"}, {0x05b6, "segol13"}, {0x05b6, "segol1f"}, {0x05b6, "segol2c"}, {0x05b6, "segolhebrew"}, {0x05b6, "segolnarrowhebrew"}, {0x05b6, "segolquarterhebrew"}, {0x0592, "segoltahebrew"}, {0x05b6, "segolwidehebrew"}, {0x057d, "seharmenian"}, {0x305b, "sehiragana"}, {0x30bb, "sekatakana"}, {0xff7e, "sekatakanahalfwidth"}, {0x003b, "semicolon"}, {0x061b, "semicolonarabic"}, {0xff1b, "semicolonmonospace"}, {0xfe54, "semicolonsmall"}, {0x309c, "semivoicedmarkkana"}, {0xff9f, "semivoicedmarkkanahalfwidth"}, {0x3322, "sentisquare"}, {0x3323, "sentosquare"}, {0x0037, "seven"}, {0x0667, "sevenarabic"}, {0x09ed, "sevenbengali"}, {0x2466, "sevencircle"}, {0x2790, "sevencircleinversesansserif"}, {0x096d, "sevendeva"}, {0x215e, "seveneighths"}, {0x0aed, "sevengujarati"}, {0x0a6d, "sevengurmukhi"}, {0x0667, "sevenhackarabic"}, {0x3027, "sevenhangzhou"}, {0x3226, "sevenideographicparen"}, {0x2087, "seveninferior"}, {0xff17, "sevenmonospace"}, {0xf737, "sevenoldstyle"}, {0x247a, "sevenparen"}, {0x248e, "sevenperiod"}, {0x06f7, "sevenpersian"}, {0x2176, "sevenroman"}, {0x2077, "sevensuperior"}, {0x2470, "seventeencircle"}, {0x2484, "seventeenparen"}, {0x2498, "seventeenperiod"}, {0x0e57, "seventhai"}, {0x00ad, "sfthyphen"}, {0x0577, "shaarmenian"}, {0x09b6, "shabengali"}, {0x0448, "shacyrillic"}, {0x0651, "shaddaarabic"}, {0xfc61, "shaddadammaarabic"}, {0xfc5e, "shaddadammatanarabic"}, {0xfc60, "shaddafathaarabic"}, {0xfc62, "shaddakasraarabic"}, {0xfc5f, "shaddakasratanarabic"}, {0x2592, "shade"}, {0x2593, "shadedark"}, {0x2591, "shadelight"}, {0x2592, "shademedium"}, {0x0936, "shadeva"}, {0x0ab6, "shagujarati"}, {0x0a36, "shagurmukhi"}, {0x0593, "shalshelethebrew"}, {0x3115, "shbopomofo"}, {0x0449, "shchacyrillic"}, {0x0634, "sheenarabic"}, {0xfeb6, "sheenfinalarabic"}, {0xfeb7, "sheeninitialarabic"}, {0xfeb8, "sheenmedialarabic"}, {0x03e3, "sheicoptic"}, {0x20aa, "sheqel"}, {0x20aa, "sheqelhebrew"}, {0x05b0, "sheva"}, {0x05b0, "sheva115"}, {0x05b0, "sheva15"}, {0x05b0, "sheva22"}, {0x05b0, "sheva2e"}, {0x05b0, "shevahebrew"}, {0x05b0, "shevanarrowhebrew"}, {0x05b0, "shevaquarterhebrew"}, {0x05b0, "shevawidehebrew"}, {0x04bb, "shhacyrillic"}, {0x03ed, "shimacoptic"}, {0x05e9, "shin"}, {0xfb49, "shindagesh"}, {0xfb49, "shindageshhebrew"}, {0xfb2c, "shindageshshindot"}, {0xfb2c, "shindageshshindothebrew"}, {0xfb2d, "shindageshsindot"}, {0xfb2d, "shindageshsindothebrew"}, {0x05c1, "shindothebrew"}, {0x05e9, "shinhebrew"}, {0xfb2a, "shinshindot"}, {0xfb2a, "shinshindothebrew"}, {0xfb2b, "shinsindot"}, {0xfb2b, "shinsindothebrew"}, {0x0282, "shook"}, {0x03c3, "sigma"}, {0x03c2, "sigma1"}, {0x03c2, "sigmafinal"}, {0x03f2, "sigmalunatesymbolgreek"}, {0x3057, "sihiragana"}, {0x30b7, "sikatakana"}, {0xff7c, "sikatakanahalfwidth"}, {0x05bd, "siluqhebrew"}, {0x05bd, "siluqlefthebrew"}, {0x223c, "similar"}, {0x05c2, "sindothebrew"}, {0x3274, "siosacirclekorean"}, {0x3214, "siosaparenkorean"}, {0x317e, "sioscieuckorean"}, {0x3266, "sioscirclekorean"}, {0x317a, "sioskiyeokkorean"}, {0x3145, "sioskorean"}, {0x317b, "siosnieunkorean"}, {0x3206, "siosparenkorean"}, {0x317d, "siospieupkorean"}, {0x317c, "siostikeutkorean"}, {0x0036, "six"}, {0x0666, "sixarabic"}, {0x09ec, "sixbengali"}, {0x2465, "sixcircle"}, {0x278f, "sixcircleinversesansserif"}, {0x096c, "sixdeva"}, {0x0aec, "sixgujarati"}, {0x0a6c, "sixgurmukhi"}, {0x0666, "sixhackarabic"}, {0x3026, "sixhangzhou"}, {0x3225, "sixideographicparen"}, {0x2086, "sixinferior"}, {0xff16, "sixmonospace"}, {0xf736, "sixoldstyle"}, {0x2479, "sixparen"}, {0x248d, "sixperiod"}, {0x06f6, "sixpersian"}, {0x2175, "sixroman"}, {0x2076, "sixsuperior"}, {0x246f, "sixteencircle"}, {0x09f9, "sixteencurrencydenominatorbengali"}, {0x2483, "sixteenparen"}, {0x2497, "sixteenperiod"}, {0x0e56, "sixthai"}, {0x002f, "slash"}, {0xff0f, "slashmonospace"}, {0x017f, "slong"}, {0x1e9b, "slongdotaccent"}, {0x263a, "smileface"}, {0xff53, "smonospace"}, {0x05c3, "sofpasuqhebrew"}, {0x00ad, "softhyphen"}, {0x044c, "softsigncyrillic"}, {0x305d, "sohiragana"}, {0x30bd, "sokatakana"}, {0xff7f, "sokatakanahalfwidth"}, {0x0338, "soliduslongoverlaycmb"}, {0x0337, "solidusshortoverlaycmb"}, {0x0e29, "sorusithai"}, {0x0e28, "sosalathai"}, {0x0e0b, "sosothai"}, {0x0e2a, "sosuathai"}, {0x0020, "space"}, {0x0020, "spacehackarabic"}, {0x2660, "spade"}, {0x2660, "spadesuitblack"}, {0x2664, "spadesuitwhite"}, {0x24ae, "sparen"}, {0x033b, "squarebelowcmb"}, {0x33c4, "squarecc"}, {0x339d, "squarecm"}, {0x25a9, "squarediagonalcrosshatchfill"}, {0x25a4, "squarehorizontalfill"}, {0x338f, "squarekg"}, {0x339e, "squarekm"}, {0x33ce, "squarekmcapital"}, {0x33d1, "squareln"}, {0x33d2, "squarelog"}, {0x338e, "squaremg"}, {0x33d5, "squaremil"}, {0x339c, "squaremm"}, {0x33a1, "squaremsquared"}, {0x25a6, "squareorthogonalcrosshatchfill"}, {0x25a7, "squareupperlefttolowerrightfill"}, {0x25a8, "squareupperrighttolowerleftfill"}, {0x25a5, "squareverticalfill"}, {0x25a3, "squarewhitewithsmallblack"}, {0x33db, "srsquare"}, {0x09b7, "ssabengali"}, {0x0937, "ssadeva"}, {0x0ab7, "ssagujarati"}, {0x3149, "ssangcieuckorean"}, {0x3185, "ssanghieuhkorean"}, {0x3180, "ssangieungkorean"}, {0x3132, "ssangkiyeokkorean"}, {0x3165, "ssangnieunkorean"}, {0x3143, "ssangpieupkorean"}, {0x3146, "ssangsioskorean"}, {0x3138, "ssangtikeutkorean"}, {0xf6f2, "ssuperior"}, {0x00a3, "sterling"}, {0xffe1, "sterlingmonospace"}, {0x0336, "strokelongoverlaycmb"}, {0x0335, "strokeshortoverlaycmb"}, {0x2282, "subset"}, {0x228a, "subsetnotequal"}, {0x2286, "subsetorequal"}, {0x227b, "succeeds"}, {0x220b, "suchthat"}, {0x3059, "suhiragana"}, {0x30b9, "sukatakana"}, {0xff7d, "sukatakanahalfwidth"}, {0x0652, "sukunarabic"}, {0x2211, "summation"}, {0x263c, "sun"}, {0x2283, "superset"}, {0x228b, "supersetnotequal"}, {0x2287, "supersetorequal"}, {0x33dc, "svsquare"}, {0x337c, "syouwaerasquare"}, {0x0074, "t"}, {0x09a4, "tabengali"}, {0x22a4, "tackdown"}, {0x22a3, "tackleft"}, {0x0924, "tadeva"}, {0x0aa4, "tagujarati"}, {0x0a24, "tagurmukhi"}, {0x0637, "taharabic"}, {0xfec2, "tahfinalarabic"}, {0xfec3, "tahinitialarabic"}, {0x305f, "tahiragana"}, {0xfec4, "tahmedialarabic"}, {0x337d, "taisyouerasquare"}, {0x30bf, "takatakana"}, {0xff80, "takatakanahalfwidth"}, {0x0640, "tatweelarabic"}, {0x03c4, "tau"}, {0x05ea, "tav"}, {0xfb4a, "tavdages"}, {0xfb4a, "tavdagesh"}, {0xfb4a, "tavdageshhebrew"}, {0x05ea, "tavhebrew"}, {0x0167, "tbar"}, {0x310a, "tbopomofo"}, {0x0165, "tcaron"}, {0x02a8, "tccurl"}, {0x0163, "tcedilla"}, {0x0686, "tcheharabic"}, {0xfb7b, "tchehfinalarabic"}, {0xfb7c, "tchehinitialarabic"}, {0xfb7d, "tchehmedialarabic"}, {0x24e3, "tcircle"}, {0x1e71, "tcircumflexbelow"}, {0x0163, "tcommaaccent"}, {0x1e97, "tdieresis"}, {0x1e6b, "tdotaccent"}, {0x1e6d, "tdotbelow"}, {0x0442, "tecyrillic"}, {0x04ad, "tedescendercyrillic"}, {0x062a, "teharabic"}, {0xfe96, "tehfinalarabic"}, {0xfca2, "tehhahinitialarabic"}, {0xfc0c, "tehhahisolatedarabic"}, {0xfe97, "tehinitialarabic"}, {0x3066, "tehiragana"}, {0xfca1, "tehjeeminitialarabic"}, {0xfc0b, "tehjeemisolatedarabic"}, {0x0629, "tehmarbutaarabic"}, {0xfe94, "tehmarbutafinalarabic"}, {0xfe98, "tehmedialarabic"}, {0xfca4, "tehmeeminitialarabic"}, {0xfc0e, "tehmeemisolatedarabic"}, {0xfc73, "tehnoonfinalarabic"}, {0x30c6, "tekatakana"}, {0xff83, "tekatakanahalfwidth"}, {0x2121, "telephone"}, {0x260e, "telephoneblack"}, {0x05a0, "telishagedolahebrew"}, {0x05a9, "telishaqetanahebrew"}, {0x2469, "tencircle"}, {0x3229, "tenideographicparen"}, {0x247d, "tenparen"}, {0x2491, "tenperiod"}, {0x2179, "tenroman"}, {0x02a7, "tesh"}, {0x05d8, "tet"}, {0xfb38, "tetdagesh"}, {0xfb38, "tetdageshhebrew"}, {0x05d8, "tethebrew"}, {0x04b5, "tetsecyrillic"}, {0x059b, "tevirhebrew"}, {0x059b, "tevirlefthebrew"}, {0x09a5, "thabengali"}, {0x0925, "thadeva"}, {0x0aa5, "thagujarati"}, {0x0a25, "thagurmukhi"}, {0x0630, "thalarabic"}, {0xfeac, "thalfinalarabic"}, {0xf898, "thanthakhatlowleftthai"}, {0xf897, "thanthakhatlowrightthai"}, {0x0e4c, "thanthakhatthai"}, {0xf896, "thanthakhatupperleftthai"}, {0x062b, "theharabic"}, {0xfe9a, "thehfinalarabic"}, {0xfe9b, "thehinitialarabic"}, {0xfe9c, "thehmedialarabic"}, {0x2203, "thereexists"}, {0x2234, "therefore"}, {0x03b8, "theta"}, {0x03d1, "theta1"}, {0x03d1, "thetasymbolgreek"}, {0x3279, "thieuthacirclekorean"}, {0x3219, "thieuthaparenkorean"}, {0x326b, "thieuthcirclekorean"}, {0x314c, "thieuthkorean"}, {0x320b, "thieuthparenkorean"}, {0x246c, "thirteencircle"}, {0x2480, "thirteenparen"}, {0x2494, "thirteenperiod"}, {0x0e11, "thonangmonthothai"}, {0x01ad, "thook"}, {0x0e12, "thophuthaothai"}, {0x00fe, "thorn"}, {0x0e17, "thothahanthai"}, {0x0e10, "thothanthai"}, {0x0e18, "thothongthai"}, {0x0e16, "thothungthai"}, {0x0482, "thousandcyrillic"}, {0x066c, "thousandsseparatorarabic"}, {0x066c, "thousandsseparatorpersian"}, {0x0033, "three"}, {0x0663, "threearabic"}, {0x09e9, "threebengali"}, {0x2462, "threecircle"}, {0x278c, "threecircleinversesansserif"}, {0x0969, "threedeva"}, {0x215c, "threeeighths"}, {0x0ae9, "threegujarati"}, {0x0a69, "threegurmukhi"}, {0x0663, "threehackarabic"}, {0x3023, "threehangzhou"}, {0x3222, "threeideographicparen"}, {0x2083, "threeinferior"}, {0xff13, "threemonospace"}, {0x09f6, "threenumeratorbengali"}, {0xf733, "threeoldstyle"}, {0x2476, "threeparen"}, {0x248a, "threeperiod"}, {0x06f3, "threepersian"}, {0x00be, "threequarters"}, {0xf6de, "threequartersemdash"}, {0x2172, "threeroman"}, {0x00b3, "threesuperior"}, {0x0e53, "threethai"}, {0x3394, "thzsquare"}, {0x3061, "tihiragana"}, {0x30c1, "tikatakana"}, {0xff81, "tikatakanahalfwidth"}, {0x3270, "tikeutacirclekorean"}, {0x3210, "tikeutaparenkorean"}, {0x3262, "tikeutcirclekorean"}, {0x3137, "tikeutkorean"}, {0x3202, "tikeutparenkorean"}, {0x02dc, "tilde"}, {0x0330, "tildebelowcmb"}, {0x0303, "tildecmb"}, {0x0303, "tildecomb"}, {0x0360, "tildedoublecmb"}, {0x223c, "tildeoperator"}, {0x0334, "tildeoverlaycmb"}, {0x033e, "tildeverticalcmb"}, {0x2297, "timescircle"}, {0x0596, "tipehahebrew"}, {0x0596, "tipehalefthebrew"}, {0x0a70, "tippigurmukhi"}, {0x0483, "titlocyrilliccmb"}, {0x057f, "tiwnarmenian"}, {0x1e6f, "tlinebelow"}, {0xff54, "tmonospace"}, {0x0569, "toarmenian"}, {0x3068, "tohiragana"}, {0x30c8, "tokatakana"}, {0xff84, "tokatakanahalfwidth"}, {0x02e5, "tonebarextrahighmod"}, {0x02e9, "tonebarextralowmod"}, {0x02e6, "tonebarhighmod"}, {0x02e8, "tonebarlowmod"}, {0x02e7, "tonebarmidmod"}, {0x01bd, "tonefive"}, {0x0185, "tonesix"}, {0x01a8, "tonetwo"}, {0x0384, "tonos"}, {0x3327, "tonsquare"}, {0x0e0f, "topatakthai"}, {0x3014, "tortoiseshellbracketleft"}, {0xfe5d, "tortoiseshellbracketleftsmall"}, {0xfe39, "tortoiseshellbracketleftvertical"}, {0x3015, "tortoiseshellbracketright"}, {0xfe5e, "tortoiseshellbracketrightsmall"}, {0xfe3a, "tortoiseshellbracketrightvertical"}, {0x0e15, "totaothai"}, {0x01ab, "tpalatalhook"}, {0x24af, "tparen"}, {0x2122, "trademark"}, {0x2122, "trademarksans"}, {0x2122, "trademarkserif"}, {0x0288, "tretroflexhook"}, {0x25bc, "triagdn"}, {0x25c4, "triaglf"}, {0x25ba, "triagrt"}, {0x25b2, "triagup"}, {0x02a6, "ts"}, {0x05e6, "tsadi"}, {0xfb46, "tsadidagesh"}, {0xfb46, "tsadidageshhebrew"}, {0x05e6, "tsadihebrew"}, {0x0446, "tsecyrillic"}, {0x05b5, "tsere"}, {0x05b5, "tsere12"}, {0x05b5, "tsere1e"}, {0x05b5, "tsere2b"}, {0x05b5, "tserehebrew"}, {0x05b5, "tserenarrowhebrew"}, {0x05b5, "tserequarterhebrew"}, {0x05b5, "tserewidehebrew"}, {0x045b, "tshecyrillic"}, {0xf6f3, "tsuperior"}, {0x099f, "ttabengali"}, {0x091f, "ttadeva"}, {0x0a9f, "ttagujarati"}, {0x0a1f, "ttagurmukhi"}, {0x0679, "tteharabic"}, {0xfb67, "ttehfinalarabic"}, {0xfb68, "ttehinitialarabic"}, {0xfb69, "ttehmedialarabic"}, {0x09a0, "tthabengali"}, {0x0920, "tthadeva"}, {0x0aa0, "tthagujarati"}, {0x0a20, "tthagurmukhi"}, {0x0287, "tturned"}, {0x3064, "tuhiragana"}, {0x30c4, "tukatakana"}, {0xff82, "tukatakanahalfwidth"}, {0x3063, "tusmallhiragana"}, {0x30c3, "tusmallkatakana"}, {0xff6f, "tusmallkatakanahalfwidth"}, {0x246b, "twelvecircle"}, {0x247f, "twelveparen"}, {0x2493, "twelveperiod"}, {0x217b, "twelveroman"}, {0x2473, "twentycircle"}, {0x5344, "twentyhangzhou"}, {0x2487, "twentyparen"}, {0x249b, "twentyperiod"}, {0x0032, "two"}, {0x0662, "twoarabic"}, {0x09e8, "twobengali"}, {0x2461, "twocircle"}, {0x278b, "twocircleinversesansserif"}, {0x0968, "twodeva"}, {0x2025, "twodotenleader"}, {0x2025, "twodotleader"}, {0xfe30, "twodotleadervertical"}, {0x0ae8, "twogujarati"}, {0x0a68, "twogurmukhi"}, {0x0662, "twohackarabic"}, {0x3022, "twohangzhou"}, {0x3221, "twoideographicparen"}, {0x2082, "twoinferior"}, {0xff12, "twomonospace"}, {0x09f5, "twonumeratorbengali"}, {0xf732, "twooldstyle"}, {0x2475, "twoparen"}, {0x2489, "twoperiod"}, {0x06f2, "twopersian"}, {0x2171, "tworoman"}, {0x01bb, "twostroke"}, {0x00b2, "twosuperior"}, {0x0e52, "twothai"}, {0x2154, "twothirds"}, {0x0075, "u"}, {0x00fa, "uacute"}, {0x0289, "ubar"}, {0x0989, "ubengali"}, {0x3128, "ubopomofo"}, {0x016d, "ubreve"}, {0x01d4, "ucaron"}, {0x24e4, "ucircle"}, {0x00fb, "ucircumflex"}, {0x1e77, "ucircumflexbelow"}, {0x0443, "ucyrillic"}, {0x0951, "udattadeva"}, {0x0171, "udblacute"}, {0x0215, "udblgrave"}, {0x0909, "udeva"}, {0x00fc, "udieresis"}, {0x01d8, "udieresisacute"}, {0x1e73, "udieresisbelow"}, {0x01da, "udieresiscaron"}, {0x04f1, "udieresiscyrillic"}, {0x01dc, "udieresisgrave"}, {0x01d6, "udieresismacron"}, {0x1ee5, "udotbelow"}, {0x00f9, "ugrave"}, {0x0a89, "ugujarati"}, {0x0a09, "ugurmukhi"}, {0x3046, "uhiragana"}, {0x1ee7, "uhookabove"}, {0x01b0, "uhorn"}, {0x1ee9, "uhornacute"}, {0x1ef1, "uhorndotbelow"}, {0x1eeb, "uhorngrave"}, {0x1eed, "uhornhookabove"}, {0x1eef, "uhorntilde"}, {0x0171, "uhungarumlaut"}, {0x04f3, "uhungarumlautcyrillic"}, {0x0217, "uinvertedbreve"}, {0x30a6, "ukatakana"}, {0xff73, "ukatakanahalfwidth"}, {0x0479, "ukcyrillic"}, {0x315c, "ukorean"}, {0x016b, "umacron"}, {0x04ef, "umacroncyrillic"}, {0x1e7b, "umacrondieresis"}, {0x0a41, "umatragurmukhi"}, {0xff55, "umonospace"}, {0x005f, "underscore"}, {0x2017, "underscoredbl"}, {0xff3f, "underscoremonospace"}, {0xfe33, "underscorevertical"}, {0xfe4f, "underscorewavy"}, {0x222a, "union"}, {0x2200, "universal"}, {0x0173, "uogonek"}, {0x24b0, "uparen"}, {0x2580, "upblock"}, {0x05c4, "upperdothebrew"}, {0x03c5, "upsilon"}, {0x03cb, "upsilondieresis"}, {0x03b0, "upsilondieresistonos"}, {0x028a, "upsilonlatin"}, {0x03cd, "upsilontonos"}, {0x031d, "uptackbelowcmb"}, {0x02d4, "uptackmod"}, {0x0a73, "uragurmukhi"}, {0x016f, "uring"}, {0x045e, "ushortcyrillic"}, {0x3045, "usmallhiragana"}, {0x30a5, "usmallkatakana"}, {0xff69, "usmallkatakanahalfwidth"}, {0x04af, "ustraightcyrillic"}, {0x04b1, "ustraightstrokecyrillic"}, {0x0169, "utilde"}, {0x1e79, "utildeacute"}, {0x1e75, "utildebelow"}, {0x098a, "uubengali"}, {0x090a, "uudeva"}, {0x0a8a, "uugujarati"}, {0x0a0a, "uugurmukhi"}, {0x0a42, "uumatragurmukhi"}, {0x09c2, "uuvowelsignbengali"}, {0x0942, "uuvowelsigndeva"}, {0x0ac2, "uuvowelsigngujarati"}, {0x09c1, "uvowelsignbengali"}, {0x0941, "uvowelsigndeva"}, {0x0ac1, "uvowelsigngujarati"}, {0x0076, "v"}, {0x0935, "vadeva"}, {0x0ab5, "vagujarati"}, {0x0a35, "vagurmukhi"}, {0x30f7, "vakatakana"}, {0x05d5, "vav"}, {0xfb35, "vavdagesh"}, {0xfb35, "vavdagesh65"}, {0xfb35, "vavdageshhebrew"}, {0x05d5, "vavhebrew"}, {0xfb4b, "vavholam"}, {0xfb4b, "vavholamhebrew"}, {0x05f0, "vavvavhebrew"}, {0x05f1, "vavyodhebrew"}, {0x24e5, "vcircle"}, {0x1e7f, "vdotbelow"}, {0x0432, "vecyrillic"}, {0x06a4, "veharabic"}, {0xfb6b, "vehfinalarabic"}, {0xfb6c, "vehinitialarabic"}, {0xfb6d, "vehmedialarabic"}, {0x30f9, "vekatakana"}, {0x2640, "venus"}, {0x007c, "verticalbar"}, {0x030d, "verticallineabovecmb"}, {0x0329, "verticallinebelowcmb"}, {0x02cc, "verticallinelowmod"}, {0x02c8, "verticallinemod"}, {0x057e, "vewarmenian"}, {0x028b, "vhook"}, {0x30f8, "vikatakana"}, {0x09cd, "viramabengali"}, {0x094d, "viramadeva"}, {0x0acd, "viramagujarati"}, {0x0983, "visargabengali"}, {0x0903, "visargadeva"}, {0x0a83, "visargagujarati"}, {0xff56, "vmonospace"}, {0x0578, "voarmenian"}, {0x309e, "voicediterationhiragana"}, {0x30fe, "voicediterationkatakana"}, {0x309b, "voicedmarkkana"}, {0xff9e, "voicedmarkkanahalfwidth"}, {0x30fa, "vokatakana"}, {0x24b1, "vparen"}, {0x1e7d, "vtilde"}, {0x028c, "vturned"}, {0x3094, "vuhiragana"}, {0x30f4, "vukatakana"}, {0x0077, "w"}, {0x1e83, "wacute"}, {0x3159, "waekorean"}, {0x308f, "wahiragana"}, {0x30ef, "wakatakana"}, {0xff9c, "wakatakanahalfwidth"}, {0x3158, "wakorean"}, {0x308e, "wasmallhiragana"}, {0x30ee, "wasmallkatakana"}, {0x3357, "wattosquare"}, {0x301c, "wavedash"}, {0xfe34, "wavyunderscorevertical"}, {0x0648, "wawarabic"}, {0xfeee, "wawfinalarabic"}, {0x0624, "wawhamzaabovearabic"}, {0xfe86, "wawhamzaabovefinalarabic"}, {0x33dd, "wbsquare"}, {0x24e6, "wcircle"}, {0x0175, "wcircumflex"}, {0x1e85, "wdieresis"}, {0x1e87, "wdotaccent"}, {0x1e89, "wdotbelow"}, {0x3091, "wehiragana"}, {0x2118, "weierstrass"}, {0x30f1, "wekatakana"}, {0x315e, "wekorean"}, {0x315d, "weokorean"}, {0x1e81, "wgrave"}, {0x25e6, "whitebullet"}, {0x25cb, "whitecircle"}, {0x25d9, "whitecircleinverse"}, {0x300e, "whitecornerbracketleft"}, {0xfe43, "whitecornerbracketleftvertical"}, {0x300f, "whitecornerbracketright"}, {0xfe44, "whitecornerbracketrightvertical"}, {0x25c7, "whitediamond"}, {0x25c8, "whitediamondcontainingblacksmalldiamond"}, {0x25bf, "whitedownpointingsmalltriangle"}, {0x25bd, "whitedownpointingtriangle"}, {0x25c3, "whiteleftpointingsmalltriangle"}, {0x25c1, "whiteleftpointingtriangle"}, {0x3016, "whitelenticularbracketleft"}, {0x3017, "whitelenticularbracketright"}, {0x25b9, "whiterightpointingsmalltriangle"}, {0x25b7, "whiterightpointingtriangle"}, {0x25ab, "whitesmallsquare"}, {0x263a, "whitesmilingface"}, {0x25a1, "whitesquare"}, {0x2606, "whitestar"}, {0x260f, "whitetelephone"}, {0x3018, "whitetortoiseshellbracketleft"}, {0x3019, "whitetortoiseshellbracketright"}, {0x25b5, "whiteuppointingsmalltriangle"}, {0x25b3, "whiteuppointingtriangle"}, {0x3090, "wihiragana"}, {0x30f0, "wikatakana"}, {0x315f, "wikorean"}, {0xff57, "wmonospace"}, {0x3092, "wohiragana"}, {0x30f2, "wokatakana"}, {0xff66, "wokatakanahalfwidth"}, {0x20a9, "won"}, {0xffe6, "wonmonospace"}, {0x0e27, "wowaenthai"}, {0x24b2, "wparen"}, {0x1e98, "wring"}, {0x02b7, "wsuperior"}, {0x028d, "wturned"}, {0x01bf, "wynn"}, {0x0078, "x"}, {0x033d, "xabovecmb"}, {0x3112, "xbopomofo"}, {0x24e7, "xcircle"}, {0x1e8d, "xdieresis"}, {0x1e8b, "xdotaccent"}, {0x056d, "xeharmenian"}, {0x03be, "xi"}, {0xff58, "xmonospace"}, {0x24b3, "xparen"}, {0x02e3, "xsuperior"}, {0x0079, "y"}, {0x334e, "yaadosquare"}, {0x09af, "yabengali"}, {0x00fd, "yacute"}, {0x092f, "yadeva"}, {0x3152, "yaekorean"}, {0x0aaf, "yagujarati"}, {0x0a2f, "yagurmukhi"}, {0x3084, "yahiragana"}, {0x30e4, "yakatakana"}, {0xff94, "yakatakanahalfwidth"}, {0x3151, "yakorean"}, {0x0e4e, "yamakkanthai"}, {0x3083, "yasmallhiragana"}, {0x30e3, "yasmallkatakana"}, {0xff6c, "yasmallkatakanahalfwidth"}, {0x0463, "yatcyrillic"}, {0x24e8, "ycircle"}, {0x0177, "ycircumflex"}, {0x00ff, "ydieresis"}, {0x1e8f, "ydotaccent"}, {0x1ef5, "ydotbelow"}, {0x064a, "yeharabic"}, {0x06d2, "yehbarreearabic"}, {0xfbaf, "yehbarreefinalarabic"}, {0xfef2, "yehfinalarabic"}, {0x0626, "yehhamzaabovearabic"}, {0xfe8a, "yehhamzaabovefinalarabic"}, {0xfe8b, "yehhamzaaboveinitialarabic"}, {0xfe8c, "yehhamzaabovemedialarabic"}, {0xfef3, "yehinitialarabic"}, {0xfef4, "yehmedialarabic"}, {0xfcdd, "yehmeeminitialarabic"}, {0xfc58, "yehmeemisolatedarabic"}, {0xfc94, "yehnoonfinalarabic"}, {0x06d1, "yehthreedotsbelowarabic"}, {0x3156, "yekorean"}, {0x00a5, "yen"}, {0xffe5, "yenmonospace"}, {0x3155, "yeokorean"}, {0x3186, "yeorinhieuhkorean"}, {0x05aa, "yerahbenyomohebrew"}, {0x05aa, "yerahbenyomolefthebrew"}, {0x044b, "yericyrillic"}, {0x04f9, "yerudieresiscyrillic"}, {0x3181, "yesieungkorean"}, {0x3183, "yesieungpansioskorean"}, {0x3182, "yesieungsioskorean"}, {0x059a, "yetivhebrew"}, {0x1ef3, "ygrave"}, {0x01b4, "yhook"}, {0x1ef7, "yhookabove"}, {0x0575, "yiarmenian"}, {0x0457, "yicyrillic"}, {0x3162, "yikorean"}, {0x262f, "yinyang"}, {0x0582, "yiwnarmenian"}, {0xff59, "ymonospace"}, {0x05d9, "yod"}, {0xfb39, "yoddagesh"}, {0xfb39, "yoddageshhebrew"}, {0x05d9, "yodhebrew"}, {0x05f2, "yodyodhebrew"}, {0xfb1f, "yodyodpatahhebrew"}, {0x3088, "yohiragana"}, {0x3189, "yoikorean"}, {0x30e8, "yokatakana"}, {0xff96, "yokatakanahalfwidth"}, {0x315b, "yokorean"}, {0x3087, "yosmallhiragana"}, {0x30e7, "yosmallkatakana"}, {0xff6e, "yosmallkatakanahalfwidth"}, {0x03f3, "yotgreek"}, {0x3188, "yoyaekorean"}, {0x3187, "yoyakorean"}, {0x0e22, "yoyakthai"}, {0x0e0d, "yoyingthai"}, {0x24b4, "yparen"}, {0x037a, "ypogegrammeni"}, {0x0345, "ypogegrammenigreekcmb"}, {0x01a6, "yr"}, {0x1e99, "yring"}, {0x02b8, "ysuperior"}, {0x1ef9, "ytilde"}, {0x028e, "yturned"}, {0x3086, "yuhiragana"}, {0x318c, "yuikorean"}, {0x30e6, "yukatakana"}, {0xff95, "yukatakanahalfwidth"}, {0x3160, "yukorean"}, {0x046b, "yusbigcyrillic"}, {0x046d, "yusbigiotifiedcyrillic"}, {0x0467, "yuslittlecyrillic"}, {0x0469, "yuslittleiotifiedcyrillic"}, {0x3085, "yusmallhiragana"}, {0x30e5, "yusmallkatakana"}, {0xff6d, "yusmallkatakanahalfwidth"}, {0x318b, "yuyekorean"}, {0x318a, "yuyeokorean"}, {0x09df, "yyabengali"}, {0x095f, "yyadeva"}, {0x007a, "z"}, {0x0566, "zaarmenian"}, {0x017a, "zacute"}, {0x095b, "zadeva"}, {0x0a5b, "zagurmukhi"}, {0x0638, "zaharabic"}, {0xfec6, "zahfinalarabic"}, {0xfec7, "zahinitialarabic"}, {0x3056, "zahiragana"}, {0xfec8, "zahmedialarabic"}, {0x0632, "zainarabic"}, {0xfeb0, "zainfinalarabic"}, {0x30b6, "zakatakana"}, {0x0595, "zaqefgadolhebrew"}, {0x0594, "zaqefqatanhebrew"}, {0x0598, "zarqahebrew"}, {0x05d6, "zayin"}, {0xfb36, "zayindagesh"}, {0xfb36, "zayindageshhebrew"}, {0x05d6, "zayinhebrew"}, {0x3117, "zbopomofo"}, {0x017e, "zcaron"}, {0x24e9, "zcircle"}, {0x1e91, "zcircumflex"}, {0x0291, "zcurl"}, {0x017c, "zdot"}, {0x017c, "zdotaccent"}, {0x1e93, "zdotbelow"}, {0x0437, "zecyrillic"}, {0x0499, "zedescendercyrillic"}, {0x04df, "zedieresiscyrillic"}, {0x305c, "zehiragana"}, {0x30bc, "zekatakana"}, {0x0030, "zero"}, {0x0660, "zeroarabic"}, {0x09e6, "zerobengali"}, {0x0966, "zerodeva"}, {0x0ae6, "zerogujarati"}, {0x0a66, "zerogurmukhi"}, {0x0660, "zerohackarabic"}, {0x2080, "zeroinferior"}, {0xff10, "zeromonospace"}, {0xf730, "zerooldstyle"}, {0x06f0, "zeropersian"}, {0x2070, "zerosuperior"}, {0x0e50, "zerothai"}, {0xfeff, "zerowidthjoiner"}, {0x200c, "zerowidthnonjoiner"}, {0x200b, "zerowidthspace"}, {0x03b6, "zeta"}, {0x3113, "zhbopomofo"}, {0x056a, "zhearmenian"}, {0x04c2, "zhebrevecyrillic"}, {0x0436, "zhecyrillic"}, {0x0497, "zhedescendercyrillic"}, {0x04dd, "zhedieresiscyrillic"}, {0x3058, "zihiragana"}, {0x30b8, "zikatakana"}, {0x05ae, "zinorhebrew"}, {0x1e95, "zlinebelow"}, {0xff5a, "zmonospace"}, {0x305e, "zohiragana"}, {0x30be, "zokatakana"}, {0x24b5, "zparen"}, {0x0290, "zretroflexhook"}, {0x01b6, "zstroke"}, {0x305a, "zuhiragana"}, {0x30ba, "zukatakana"}, {0x007b, "{"}, {0x007c, "|"}, {0x007d, "}"}, {0x007e, "~"}, { 0, NULL } }; xpdf-3.03/xpdf/XPDFViewer.h0000644000076400007640000003104411622305345014752 0ustar dereknderekn//======================================================================== // // XPDFViewer.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XPDFVIEWER_H #define XPDFVIEWER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #define Object XtObject #include #undef Object #include "gtypes.h" #include "XPDFCore.h" #if (XmVERSION <= 1) && !defined(__sgi) #define DISABLE_OUTLINE #endif #if (XmVERSION >= 2 && !defined(LESSTIF_VERSION)) # define USE_COMBO_BOX 1 #else # undef USE_COMBO_BOX #endif class GString; class GList; class UnicodeMap; class LinkDest; class XPDFApp; class XPDFViewer; //------------------------------------------------------------------------ // NB: this must match the defn of zoomMenuBtnInfo in XPDFViewer.cc #define nZoomMenuItems 10 //------------------------------------------------------------------------ struct XPDFViewerCmd { const char *name; int nArgs; GBool requiresDoc; GBool requiresEvent; void (XPDFViewer::*func)(GString *args[], int nArgs, XEvent *event); }; //------------------------------------------------------------------------ // XPDFViewer //------------------------------------------------------------------------ class XPDFViewer { public: XPDFViewer(XPDFApp *appA, GString *fileName, int pageA, GString *destName, GBool fullScreen, GString *ownerPassword, GString *userPassword); XPDFViewer(XPDFApp *appA, PDFDoc *doc, int pageA, GString *destName, GBool fullScreen); GBool isOk() { return ok; } ~XPDFViewer(); void open(GString *fileName, int pageA, GString *destName); void clear(); void reloadFile(); void execCmd(GString *cmd, XEvent *event); Widget getWindow() { return win; } private: //----- load / display GBool loadFile(GString *fileName, GString *ownerPassword = NULL, GString *userPassword = NULL); void displayPage(int pageA, double zoomA, int rotateA, GBool scrollToTop, GBool addToHist); void displayDest(LinkDest *dest, double zoomA, int rotateA, GBool addToHist); void getPageAndDest(int pageA, GString *destName, int *pageOut, LinkDest **destOut); //----- hyperlinks / actions void doLink(int wx, int wy, GBool onlyIfNoSelection, GBool newWin); static void actionCbk(void *data, char *action); //----- keyboard/mouse input static void keyPressCbk(void *data, KeySym key, Guint modifiers, XEvent *event); static void mouseCbk(void *data, XEvent *event); int getModifiers(Guint modifiers); int getContext(Guint modifiers); //----- command functions void cmdAbout(GString *args[], int nArgs, XEvent *event); void cmdCloseOutline(GString *args[], int nArgs, XEvent *event); void cmdCloseWindow(GString *args[], int nArgs, XEvent *event); void cmdContinuousMode(GString *args[], int nArgs, XEvent *event); void cmdEndPan(GString *args[], int nArgs, XEvent *event); void cmdEndSelection(GString *args[], int nArgs, XEvent *event); void cmdFind(GString *args[], int nArgs, XEvent *event); void cmdFindNext(GString *args[], int nArgs, XEvent *event); void cmdFocusToDocWin(GString *args[], int nArgs, XEvent *event); void cmdFocusToPageNum(GString *args[], int nArgs, XEvent *event); void cmdFollowLink(GString *args[], int nArgs, XEvent *event); void cmdFollowLinkInNewWin(GString *args[], int nArgs, XEvent *event); void cmdFollowLinkInNewWinNoSel(GString *args[], int nArgs, XEvent *event); void cmdFollowLinkNoSel(GString *args[], int nArgs, XEvent *event); void cmdFullScreenMode(GString *args[], int nArgs, XEvent *event); void cmdGoBackward(GString *args[], int nArgs, XEvent *event); void cmdGoForward(GString *args[], int nArgs, XEvent *event); void cmdGotoDest(GString *args[], int nArgs, XEvent *event); void cmdGotoLastPage(GString *args[], int nArgs, XEvent *event); void cmdGotoLastPageNoScroll(GString *args[], int nArgs, XEvent *event); void cmdGotoPage(GString *args[], int nArgs, XEvent *event); void cmdGotoPageNoScroll(GString *args[], int nArgs, XEvent *event); void cmdNextPage(GString *args[], int nArgs, XEvent *event); void cmdNextPageNoScroll(GString *args[], int nArgs, XEvent *event); void cmdOpen(GString *args[], int nArgs, XEvent *event); void cmdOpenFile(GString *args[], int nArgs, XEvent *event); void cmdOpenFileAtDest(GString *args[], int nArgs, XEvent *event); void cmdOpenFileAtDestInNewWin(GString *args[], int nArgs, XEvent *event); void cmdOpenFileAtPage(GString *args[], int nArgs, XEvent *event); void cmdOpenFileAtPageInNewWin(GString *args[], int nArgs, XEvent *event); void cmdOpenFileInNewWin(GString *args[], int nArgs, XEvent *event); void cmdOpenInNewWin(GString *args[], int nArgs, XEvent *event); void cmdOpenOutline(GString *args[], int nArgs, XEvent *event); void cmdPageDown(GString *args[], int nArgs, XEvent *event); void cmdPageUp(GString *args[], int nArgs, XEvent *event); void cmdPostPopupMenu(GString *args[], int nArgs, XEvent *event); void cmdPrevPage(GString *args[], int nArgs, XEvent *event); void cmdPrevPageNoScroll(GString *args[], int nArgs, XEvent *event); void cmdPrint(GString *args[], int nArgs, XEvent *event); void cmdQuit(GString *args[], int nArgs, XEvent *event); void cmdRaise(GString *args[], int nArgs, XEvent *event); void cmdRedraw(GString *args[], int nArgs, XEvent *event); void cmdReload(GString *args[], int nArgs, XEvent *event); void cmdRotateCCW(GString *args[], int nArgs, XEvent *event); void cmdRotateCW(GString *args[], int nArgs, XEvent *event); void cmdRun(GString *args[], int nArgs, XEvent *event); void cmdScrollDown(GString *args[], int nArgs, XEvent *event); void cmdScrollDownNextPage(GString *args[], int nArgs, XEvent *event); void cmdScrollLeft(GString *args[], int nArgs, XEvent *event); void cmdScrollOutlineDown(GString *args[], int nArgs, XEvent *event); void cmdScrollOutlineUp(GString *args[], int nArgs, XEvent *event); void cmdScrollRight(GString *args[], int nArgs, XEvent *event); void cmdScrollToBottomEdge(GString *args[], int nArgs, XEvent *event); void cmdScrollToBottomRight(GString *args[], int nArgs, XEvent *event); void cmdScrollToLeftEdge(GString *args[], int nArgs, XEvent *event); void cmdScrollToRightEdge(GString *args[], int nArgs, XEvent *event); void cmdScrollToTopEdge(GString *args[], int nArgs, XEvent *event); void cmdScrollToTopLeft(GString *args[], int nArgs, XEvent *event); void cmdScrollUp(GString *args[], int nArgs, XEvent *event); void cmdScrollUpPrevPage(GString *args[], int nArgs, XEvent *event); void cmdSetSelection(GString *args[], int nArgs, XEvent *event); void cmdSinglePageMode(GString *args[], int nArgs, XEvent *event); void cmdStartPan(GString *args[], int nArgs, XEvent *event); void cmdStartSelection(GString *args[], int nArgs, XEvent *event); void cmdToggleContinuousMode(GString *args[], int nArgs, XEvent *event); void cmdToggleFullScreenMode(GString *args[], int nArgs, XEvent *event); void cmdToggleOutline(GString *args[], int nArgs, XEvent *event); void cmdWindowMode(GString *args[], int nArgs, XEvent *event); void cmdZoomFitPage(GString *args[], int nArgs, XEvent *event); void cmdZoomFitWidth(GString *args[], int nArgs, XEvent *event); void cmdZoomIn(GString *args[], int nArgs, XEvent *event); void cmdZoomOut(GString *args[], int nArgs, XEvent *event); void cmdZoomPercent(GString *args[], int nArgs, XEvent *event); void cmdZoomToSelection(GString *args[], int nArgs, XEvent *event); //----- GUI code: main window void initWindow(GBool fullScreen); void initToolbar(Widget parent); #ifndef DISABLE_OUTLINE void initPanedWin(Widget parent); #endif void initCore(Widget parent, GBool fullScreen); void initPopupMenu(); void addToolTip(Widget widget, char *text); void mapWindow(); void closeWindow(); int getZoomIdx(); void setZoomIdx(int idx); void setZoomVal(double z); static void prevPageCbk(Widget widget, XtPointer ptr, XtPointer callData); static void prevTenPageCbk(Widget widget, XtPointer ptr, XtPointer callData); static void nextPageCbk(Widget widget, XtPointer ptr, XtPointer callData); static void nextTenPageCbk(Widget widget, XtPointer ptr, XtPointer callData); static void backCbk(Widget widget, XtPointer ptr, XtPointer callData); static void forwardCbk(Widget widget, XtPointer ptr, XtPointer callData); #if USE_COMBO_BOX static void zoomComboBoxCbk(Widget widget, XtPointer ptr, XtPointer callData); #else static void zoomMenuCbk(Widget widget, XtPointer ptr, XtPointer callData); #endif static void findCbk(Widget widget, XtPointer ptr, XtPointer callData); static void printCbk(Widget widget, XtPointer ptr, XtPointer callData); static void aboutCbk(Widget widget, XtPointer ptr, XtPointer callData); static void quitCbk(Widget widget, XtPointer ptr, XtPointer callData); static void openCbk(Widget widget, XtPointer ptr, XtPointer callData); static void openInNewWindowCbk(Widget widget, XtPointer ptr, XtPointer callData); static void reloadCbk(Widget widget, XtPointer ptr, XtPointer callData); static void saveAsCbk(Widget widget, XtPointer ptr, XtPointer callData); static void continuousModeToggleCbk(Widget widget, XtPointer ptr, XtPointer callData); static void fullScreenToggleCbk(Widget widget, XtPointer ptr, XtPointer callData); static void rotateCCWCbk(Widget widget, XtPointer ptr, XtPointer callData); static void rotateCWCbk(Widget widget, XtPointer ptr, XtPointer callData); static void zoomToSelectionCbk(Widget widget, XtPointer ptr, XtPointer callData); static void closeCbk(Widget widget, XtPointer ptr, XtPointer callData); static void closeMsgCbk(Widget widget, XtPointer ptr, XtPointer callData); static void pageNumCbk(Widget widget, XtPointer ptr, XtPointer callData); static void updateCbk(void *data, GString *fileName, int pageNum, int numPages, const char *linkString); //----- GUI code: outline #ifndef DISABLE_OUTLINE void setupOutline(); void setupOutlineItems(GList *items, Widget parent, UnicodeMap *uMap); static void outlineSelectCbk(Widget widget, XtPointer ptr, XtPointer callData); #endif //----- GUI code: "about" dialog void initAboutDialog(); //----- GUI code: "open" dialog void initOpenDialog(); void mapOpenDialog(GBool openInNewWindowA); static void openOkCbk(Widget widget, XtPointer ptr, XtPointer callData); //----- GUI code: "find" dialog void initFindDialog(); static void findFindCbk(Widget widget, XtPointer ptr, XtPointer callData); void mapFindDialog(); void doFind(GBool next); static void findCloseCbk(Widget widget, XtPointer ptr, XtPointer callData); //----- GUI code: "save as" dialog void initSaveAsDialog(); void mapSaveAsDialog(); static void saveAsOkCbk(Widget widget, XtPointer ptr, XtPointer callData); //----- GUI code: "print" dialog void initPrintDialog(); void setupPrintDialog(); static void printWithCmdBtnCbk(Widget widget, XtPointer ptr, XtPointer callData); static void printToFileBtnCbk(Widget widget, XtPointer ptr, XtPointer callData); static void printPrintCbk(Widget widget, XtPointer ptr, XtPointer callData); //----- Motif support XmFontList createFontList(char *xlfd); static XPDFViewerCmd cmdTab[]; XPDFApp *app; GBool ok; Display *display; int screenNum; Widget win; // top-level window Widget form; Widget panedWin; #ifndef DISABLE_OUTLINE Widget outlineScroll; Widget outlineTree; Widget *outlineLabels; int outlineLabelsLength; int outlineLabelsSize; Dimension outlinePaneWidth; #endif XPDFCore *core; Widget toolBar; Widget backBtn; Widget prevTenPageBtn; Widget prevPageBtn; Widget nextPageBtn; Widget nextTenPageBtn; Widget forwardBtn; Widget pageNumText; Widget pageCountLabel; #if USE_COMBO_BOX Widget zoomComboBox; #else Widget zoomMenu; Widget zoomMenuBtns[nZoomMenuItems]; #endif Widget zoomWidget; Widget findBtn; Widget printBtn; Widget aboutBtn; Widget linkLabel; Widget quitBtn; Widget popupMenu; Widget aboutDialog; XmFontList aboutBigFont, aboutVersionFont, aboutFixedFont; Widget openDialog; GBool openInNewWindow; Widget findDialog; Widget findText; Widget findBackwardToggle; Widget findCaseSensitiveToggle; Widget findWholeWordToggle; Widget saveAsDialog; Widget printDialog; Widget printWithCmdBtn; Widget printToFileBtn; Widget printCmdText; Widget printFileText; Widget printFirstPage; Widget printLastPage; }; #endif xpdf-3.03/xpdf/backArrowDis.xbm0000644000076400007640000000045011622305345015736 0ustar dereknderekn#define backArrowDis_width 16 #define backArrowDis_height 15 static unsigned char backArrowDis_bits[] = { 0x80, 0x00, 0x40, 0x00, 0xa0, 0x00, 0x50, 0x00, 0xa8, 0x00, 0x54, 0x44, 0xaa, 0x88, 0x55, 0x44, 0xaa, 0x88, 0x54, 0x44, 0xa8, 0x88, 0x50, 0x00, 0xa0, 0x00, 0x40, 0x00, 0x80, 0x00}; xpdf-3.03/xpdf/JPXStream.h0000644000076400007640000002361611622305345014652 0ustar dereknderekn//======================================================================== // // JPXStream.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef JPXSTREAM_H #define JPXSTREAM_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" #include "Stream.h" class JArithmeticDecoder; class JArithmeticDecoderStats; //------------------------------------------------------------------------ enum JPXColorSpaceType { jpxCSBiLevel = 0, jpxCSYCbCr1 = 1, jpxCSYCbCr2 = 3, jpxCSYCBCr3 = 4, jpxCSPhotoYCC = 9, jpxCSCMY = 11, jpxCSCMYK = 12, jpxCSYCCK = 13, jpxCSCIELab = 14, jpxCSsRGB = 16, jpxCSGrayscale = 17, jpxCSBiLevel2 = 18, jpxCSCIEJab = 19, jpxCSCISesRGB = 20, jpxCSROMMRGB = 21, jpxCSsRGBYCbCr = 22, jpxCSYPbPr1125 = 23, jpxCSYPbPr1250 = 24 }; struct JPXColorSpecCIELab { Guint rl, ol, ra, oa, rb, ob, il; }; struct JPXColorSpecEnumerated { JPXColorSpaceType type; // color space type union { JPXColorSpecCIELab cieLab; }; }; struct JPXColorSpec { Guint meth; // method int prec; // precedence union { JPXColorSpecEnumerated enumerated; }; }; //------------------------------------------------------------------------ struct JPXPalette { Guint nEntries; // number of entries in the palette Guint nComps; // number of components in each entry Guint *bpc; // bits per component, for each component int *c; // color data: // c[i*nComps+j] = entry i, component j }; //------------------------------------------------------------------------ struct JPXCompMap { Guint nChannels; // number of channels Guint *comp; // codestream components mapped to each channel Guint *type; // 0 for direct use, 1 for palette mapping Guint *pComp; // palette components to use }; //------------------------------------------------------------------------ struct JPXChannelDefn { Guint nChannels; // number of channels Guint *idx; // channel indexes Guint *type; // channel types Guint *assoc; // channel associations }; //------------------------------------------------------------------------ struct JPXTagTreeNode { GBool finished; // true if this node is finished Guint val; // current value }; //------------------------------------------------------------------------ struct JPXCodeBlock { //----- size Guint x0, y0, x1, y1; // bounds //----- persistent state GBool seen; // true if this code-block has already // been seen Guint lBlock; // base number of bits used for pkt data length Guint nextPass; // next coding pass //---- info from first packet Guint nZeroBitPlanes; // number of zero bit planes //----- info for the current packet Guint included; // code-block inclusion in this packet: // 0=not included, 1=included Guint nCodingPasses; // number of coding passes in this pkt Guint *dataLen; // data lengths (one per codeword segment) Guint dataLenSize; // size of the dataLen array //----- coefficient data int *coeffs; char *touched; // coefficient 'touched' flags Gushort len; // coefficient length JArithmeticDecoder // arithmetic decoder *arithDecoder; JArithmeticDecoderStats // arithmetic decoder stats *stats; }; //------------------------------------------------------------------------ struct JPXSubband { //----- computed Guint x0, y0, x1, y1; // bounds Guint nXCBs, nYCBs; // number of code-blocks in the x and y // directions //----- tag trees Guint maxTTLevel; // max tag tree level JPXTagTreeNode *inclusion; // inclusion tag tree for each subband JPXTagTreeNode *zeroBitPlane; // zero-bit plane tag tree for each // subband //----- children JPXCodeBlock *cbs; // the code-blocks (len = nXCBs * nYCBs) }; //------------------------------------------------------------------------ struct JPXPrecinct { //----- computed Guint x0, y0, x1, y1; // bounds of the precinct //----- children JPXSubband *subbands; // the subbands }; //------------------------------------------------------------------------ struct JPXResLevel { //----- from the COD and COC segments (main and tile) Guint precinctWidth; // log2(precinct width) Guint precinctHeight; // log2(precinct height) //----- computed Guint x0, y0, x1, y1; // bounds of the tile-comp (for this res level) Guint bx0[3], by0[3], // subband bounds bx1[3], by1[3]; //---- children JPXPrecinct *precincts; // the precincts }; //------------------------------------------------------------------------ struct JPXTileComp { //----- from the SIZ segment GBool sgned; // 1 for signed, 0 for unsigned Guint prec; // precision, in bits Guint hSep; // horizontal separation of samples Guint vSep; // vertical separation of samples //----- from the COD and COC segments (main and tile) Guint style; // coding style parameter (Scod / Scoc) Guint nDecompLevels; // number of decomposition levels Guint codeBlockW; // log2(code-block width) Guint codeBlockH; // log2(code-block height) Guint codeBlockStyle; // code-block style Guint transform; // wavelet transformation //----- from the QCD and QCC segments (main and tile) Guint quantStyle; // quantization style Guint *quantSteps; // quantization step size for each subband Guint nQuantSteps; // number of entries in quantSteps //----- computed Guint x0, y0, x1, y1; // bounds of the tile-comp, in ref coords Guint w; // x1 - x0 Guint cbW; // code-block width Guint cbH; // code-block height //----- image data int *data; // the decoded image data int *buf; // intermediate buffer for the inverse // transform //----- children JPXResLevel *resLevels; // the resolution levels // (len = nDecompLevels + 1) }; //------------------------------------------------------------------------ struct JPXTile { GBool init; //----- from the COD segments (main and tile) Guint progOrder; // progression order Guint nLayers; // number of layers Guint multiComp; // multiple component transformation //----- computed Guint x0, y0, x1, y1; // bounds of the tile, in ref coords Guint maxNDecompLevels; // max number of decomposition levels used // in any component in this tile //----- progression order loop counters Guint comp; // component Guint res; // resolution level Guint precinct; // precinct Guint layer; // layer //----- children JPXTileComp *tileComps; // the tile-components (len = JPXImage.nComps) }; //------------------------------------------------------------------------ struct JPXImage { //----- from the SIZ segment Guint xSize, ySize; // size of reference grid Guint xOffset, yOffset; // image offset Guint xTileSize, yTileSize; // size of tiles Guint xTileOffset, // offset of first tile yTileOffset; Guint nComps; // number of components //----- computed Guint nXTiles; // number of tiles in x direction Guint nYTiles; // number of tiles in y direction //----- children JPXTile *tiles; // the tiles (len = nXTiles * nYTiles) }; //------------------------------------------------------------------------ class JPXStream: public FilterStream { public: JPXStream(Stream *strA); virtual ~JPXStream(); virtual StreamKind getKind() { return strJPX; } virtual void reset(); virtual void close(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, const char *indent); virtual GBool isBinary(GBool last = gTrue); virtual void getImageParams(int *bitsPerComponent, StreamColorSpaceMode *csMode); private: void fillReadBuf(); void getImageParams2(int *bitsPerComponent, StreamColorSpaceMode *csMode); GBool readBoxes(); GBool readColorSpecBox(Guint dataLen); GBool readCodestream(Guint len); GBool readTilePart(); GBool readTilePartData(Guint tileIdx, Guint tilePartLen, GBool tilePartToEOC); GBool readCodeBlockData(JPXTileComp *tileComp, JPXResLevel *resLevel, JPXPrecinct *precinct, JPXSubband *subband, Guint res, Guint sb, JPXCodeBlock *cb); void inverseTransform(JPXTileComp *tileComp); void inverseTransformLevel(JPXTileComp *tileComp, Guint r, JPXResLevel *resLevel); void inverseTransform1D(JPXTileComp *tileComp, int *data, Guint offset, Guint n); GBool inverseMultiCompAndDC(JPXTile *tile); GBool readBoxHdr(Guint *boxType, Guint *boxLen, Guint *dataLen); int readMarkerHdr(int *segType, Guint *segLen); GBool readUByte(Guint *x); GBool readByte(int *x); GBool readUWord(Guint *x); GBool readULong(Guint *x); GBool readNBytes(int nBytes, GBool signd, int *x); void startBitBuf(Guint byteCountA); GBool readBits(int nBits, Guint *x); void skipSOP(); void skipEPH(); Guint finishBitBuf(); BufStream *bufStr; // buffered stream (for lookahead) Guint nComps; // number of components Guint *bpc; // bits per component, for each component Guint width, height; // image size GBool haveImgHdr; // set if a JP2/JPX image header has been // found JPXColorSpec cs; // color specification GBool haveCS; // set if a color spec has been found JPXPalette palette; // the palette GBool havePalette; // set if a palette has been found JPXCompMap compMap; // the component mapping GBool haveCompMap; // set if a component mapping has been found JPXChannelDefn channelDefn; // channel definition GBool haveChannelDefn; // set if a channel defn has been found JPXImage img; // JPEG2000 decoder data Guint bitBuf; // buffer for bit reads int bitBufLen; // number of bits in bitBuf GBool bitBufSkip; // true if next bit should be skipped // (for bit stuffing) Guint byteCount; // number of available bytes left Guint curX, curY, curComp; // current position for lookChar/getChar Guint readBuf; // read buffer Guint readBufLen; // number of valid bits in readBuf }; #endif xpdf-3.03/xpdf/Function.cc0000644000076400007640000011162011622305345014751 0ustar dereknderekn//======================================================================== // // Function.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include "gmem.h" #include "Object.h" #include "Dict.h" #include "Stream.h" #include "Error.h" #include "Function.h" //------------------------------------------------------------------------ // Max depth of nested functions. This is used to catch infinite // loops in the function object structure. #define recursionLimit 8 //------------------------------------------------------------------------ // Function //------------------------------------------------------------------------ Function::Function() { } Function::~Function() { } Function *Function::parse(Object *funcObj, int recursion) { Function *func; Dict *dict; int funcType; Object obj1; if (recursion > recursionLimit) { error(errSyntaxError, -1, "Loop detected in function objects"); return NULL; } if (funcObj->isStream()) { dict = funcObj->streamGetDict(); } else if (funcObj->isDict()) { dict = funcObj->getDict(); } else if (funcObj->isName("Identity")) { return new IdentityFunction(); } else { error(errSyntaxError, -1, "Expected function dictionary or stream"); return NULL; } if (!dict->lookup("FunctionType", &obj1)->isInt()) { error(errSyntaxError, -1, "Function type is missing or wrong type"); obj1.free(); return NULL; } funcType = obj1.getInt(); obj1.free(); if (funcType == 0) { func = new SampledFunction(funcObj, dict); } else if (funcType == 2) { func = new ExponentialFunction(funcObj, dict); } else if (funcType == 3) { func = new StitchingFunction(funcObj, dict, recursion); } else if (funcType == 4) { func = new PostScriptFunction(funcObj, dict); } else { error(errSyntaxError, -1, "Unimplemented function type ({0:d})", funcType); return NULL; } if (!func->isOk()) { delete func; return NULL; } return func; } GBool Function::init(Dict *dict) { Object obj1, obj2; int i; //----- Domain if (!dict->lookup("Domain", &obj1)->isArray()) { error(errSyntaxError, -1, "Function is missing domain"); goto err2; } m = obj1.arrayGetLength() / 2; if (m > funcMaxInputs) { error(errSyntaxError, -1, "Functions with more than {0:d} inputs are unsupported", funcMaxInputs); goto err2; } for (i = 0; i < m; ++i) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function domain array"); goto err1; } domain[i][0] = obj2.getNum(); obj2.free(); obj1.arrayGet(2*i+1, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function domain array"); goto err1; } domain[i][1] = obj2.getNum(); obj2.free(); } obj1.free(); //----- Range hasRange = gFalse; n = 0; if (dict->lookup("Range", &obj1)->isArray()) { hasRange = gTrue; n = obj1.arrayGetLength() / 2; if (n > funcMaxOutputs) { error(errSyntaxError, -1, "Functions with more than {0:d} outputs are unsupported", funcMaxOutputs); goto err2; } for (i = 0; i < n; ++i) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function range array"); goto err1; } range[i][0] = obj2.getNum(); obj2.free(); obj1.arrayGet(2*i+1, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function range array"); goto err1; } range[i][1] = obj2.getNum(); obj2.free(); } } obj1.free(); return gTrue; err1: obj2.free(); err2: obj1.free(); return gFalse; } //------------------------------------------------------------------------ // IdentityFunction //------------------------------------------------------------------------ IdentityFunction::IdentityFunction() { int i; // fill these in with arbitrary values just in case they get used // somewhere m = funcMaxInputs; n = funcMaxOutputs; for (i = 0; i < funcMaxInputs; ++i) { domain[i][0] = 0; domain[i][1] = 1; } hasRange = gFalse; } IdentityFunction::~IdentityFunction() { } void IdentityFunction::transform(double *in, double *out) { int i; for (i = 0; i < funcMaxOutputs; ++i) { out[i] = in[i]; } } //------------------------------------------------------------------------ // SampledFunction //------------------------------------------------------------------------ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { Stream *str; int sampleBits; double sampleMul; Object obj1, obj2; Guint buf, bitMask; int bits; Guint s; double in[funcMaxInputs]; int i, j, t, bit, idx; idxOffset = NULL; samples = NULL; sBuf = NULL; ok = gFalse; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (!hasRange) { error(errSyntaxError, -1, "Type 0 function is missing range"); goto err1; } if (m > sampledFuncMaxInputs) { error(errSyntaxError, -1, "Sampled functions with more than {0:d} inputs are unsupported", sampledFuncMaxInputs); goto err1; } //----- buffer sBuf = (double *)gmallocn(1 << m, sizeof(double)); //----- get the stream if (!funcObj->isStream()) { error(errSyntaxError, -1, "Type 0 function isn't a stream"); goto err1; } str = funcObj->getStream(); //----- Size if (!dict->lookup("Size", &obj1)->isArray() || obj1.arrayGetLength() != m) { error(errSyntaxError, -1, "Function has missing or invalid size array"); goto err2; } for (i = 0; i < m; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isInt()) { error(errSyntaxError, -1, "Illegal value in function size array"); goto err3; } sampleSize[i] = obj2.getInt(); if (sampleSize[i] <= 0) { error(errSyntaxError, -1, "Illegal non-positive value in function size array"); goto err3; } obj2.free(); } obj1.free(); idxOffset = (int *)gmallocn(1 << m, sizeof(int)); for (i = 0; i < (1<= 1; --j, t <<= 1) { if (sampleSize[j] == 1) { bit = 0; } else { bit = (t >> (m - 1)) & 1; } idx = (idx + bit) * sampleSize[j-1]; } if (sampleSize[0] == 1) { bit = 0; } else { bit = (t >> (m - 1)) & 1; } idxOffset[i] = (idx + bit) * n; } //----- BitsPerSample if (!dict->lookup("BitsPerSample", &obj1)->isInt()) { error(errSyntaxError, -1, "Function has missing or invalid BitsPerSample"); goto err2; } sampleBits = obj1.getInt(); sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1); obj1.free(); //----- Encode if (dict->lookup("Encode", &obj1)->isArray() && obj1.arrayGetLength() == 2*m) { for (i = 0; i < m; ++i) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function encode array"); goto err3; } encode[i][0] = obj2.getNum(); obj2.free(); obj1.arrayGet(2*i+1, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function encode array"); goto err3; } encode[i][1] = obj2.getNum(); obj2.free(); } } else { for (i = 0; i < m; ++i) { encode[i][0] = 0; encode[i][1] = sampleSize[i] - 1; } } obj1.free(); for (i = 0; i < m; ++i) { inputMul[i] = (encode[i][1] - encode[i][0]) / (domain[i][1] - domain[i][0]); } //----- Decode if (dict->lookup("Decode", &obj1)->isArray() && obj1.arrayGetLength() == 2*n) { for (i = 0; i < n; ++i) { obj1.arrayGet(2*i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function decode array"); goto err3; } decode[i][0] = obj2.getNum(); obj2.free(); obj1.arrayGet(2*i+1, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function decode array"); goto err3; } decode[i][1] = obj2.getNum(); obj2.free(); } } else { for (i = 0; i < n; ++i) { decode[i][0] = range[i][0]; decode[i][1] = range[i][1]; } } obj1.free(); //----- samples nSamples = n; for (i = 0; i < m; ++i) nSamples *= sampleSize[i]; samples = (double *)gmallocn(nSamples, sizeof(double)); buf = 0; bits = 0; bitMask = (1 << sampleBits) - 1; str->reset(); for (i = 0; i < nSamples; ++i) { if (sampleBits == 8) { s = str->getChar(); } else if (sampleBits == 16) { s = str->getChar(); s = (s << 8) + str->getChar(); } else if (sampleBits == 32) { s = str->getChar(); s = (s << 8) + str->getChar(); s = (s << 8) + str->getChar(); s = (s << 8) + str->getChar(); } else { while (bits < sampleBits) { buf = (buf << 8) | (str->getChar() & 0xff); bits += 8; } s = (buf >> (bits - sampleBits)) & bitMask; bits -= sampleBits; } samples[i] = (double)s * sampleMul; } str->close(); // set up the cache for (i = 0; i < m; ++i) { in[i] = domain[i][0]; cacheIn[i] = in[i] - 1; } transform(in, cacheOut); ok = gTrue; return; err3: obj2.free(); err2: obj1.free(); err1: return; } SampledFunction::~SampledFunction() { if (idxOffset) { gfree(idxOffset); } if (samples) { gfree(samples); } if (sBuf) { gfree(sBuf); } } SampledFunction::SampledFunction(SampledFunction *func) { memcpy(this, func, sizeof(SampledFunction)); idxOffset = (int *)gmallocn(1 << m, sizeof(int)); memcpy(idxOffset, func->idxOffset, (1 << m) * (int)sizeof(int)); samples = (double *)gmallocn(nSamples, sizeof(double)); memcpy(samples, func->samples, nSamples * sizeof(double)); sBuf = (double *)gmallocn(1 << m, sizeof(double)); } void SampledFunction::transform(double *in, double *out) { double x; int e[funcMaxInputs]; double efrac0[funcMaxInputs]; double efrac1[funcMaxInputs]; int i, j, k, idx0, t; // check the cache for (i = 0; i < m; ++i) { if (in[i] != cacheIn[i]) { break; } } if (i == m) { for (i = 0; i < n; ++i) { out[i] = cacheOut[i]; } return; } // map input values into sample array for (i = 0; i < m; ++i) { x = (in[i] - domain[i][0]) * inputMul[i] + encode[i][0]; if (x < 0 || x != x) { // x!=x is a more portable version of isnan(x) x = 0; } else if (x > sampleSize[i] - 1) { x = sampleSize[i] - 1; } e[i] = (int)x; if (e[i] == sampleSize[i] - 1 && sampleSize[i] > 1) { // this happens if in[i] = domain[i][1] e[i] = sampleSize[i] - 2; } efrac1[i] = x - e[i]; efrac0[i] = 1 - efrac1[i]; } // compute index for the first sample to be used idx0 = 0; for (k = m - 1; k >= 1; --k) { idx0 = (idx0 + e[k]) * sampleSize[k-1]; } idx0 = (idx0 + e[0]) * n; // for each output, do m-linear interpolation for (i = 0; i < n; ++i) { // pull 2^m values out of the sample array for (j = 0; j < (1<>= 1) { for (k = 0; k < t; k += 2) { sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1]; } } // map output value to range out[i] = sBuf[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { out[i] = range[i][1]; } } // save current result in the cache for (i = 0; i < m; ++i) { cacheIn[i] = in[i]; } for (i = 0; i < n; ++i) { cacheOut[i] = out[i]; } } //------------------------------------------------------------------------ // ExponentialFunction //------------------------------------------------------------------------ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; int i; ok = gFalse; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (m != 1) { error(errSyntaxError, -1, "Exponential function with more than one input"); goto err1; } //----- C0 if (dict->lookup("C0", &obj1)->isArray()) { if (hasRange && obj1.arrayGetLength() != n) { error(errSyntaxError, -1, "Function's C0 array is wrong length"); goto err2; } n = obj1.arrayGetLength(); for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function C0 array"); goto err3; } c0[i] = obj2.getNum(); obj2.free(); } } else { if (hasRange && n != 1) { error(errSyntaxError, -1, "Function's C0 array is wrong length"); goto err2; } n = 1; c0[0] = 0; } obj1.free(); //----- C1 if (dict->lookup("C1", &obj1)->isArray()) { if (obj1.arrayGetLength() != n) { error(errSyntaxError, -1, "Function's C1 array is wrong length"); goto err2; } for (i = 0; i < n; ++i) { obj1.arrayGet(i, &obj2); if (!obj2.isNum()) { error(errSyntaxError, -1, "Illegal value in function C1 array"); goto err3; } c1[i] = obj2.getNum(); obj2.free(); } } else { if (n != 1) { error(errSyntaxError, -1, "Function's C1 array is wrong length"); goto err2; } c1[0] = 1; } obj1.free(); //----- N (exponent) if (!dict->lookup("N", &obj1)->isNum()) { error(errSyntaxError, -1, "Function has missing or invalid N"); goto err2; } e = obj1.getNum(); obj1.free(); ok = gTrue; return; err3: obj2.free(); err2: obj1.free(); err1: return; } ExponentialFunction::~ExponentialFunction() { } ExponentialFunction::ExponentialFunction(ExponentialFunction *func) { memcpy(this, func, sizeof(ExponentialFunction)); } void ExponentialFunction::transform(double *in, double *out) { double x; int i; if (in[0] < domain[0][0]) { x = domain[0][0]; } else if (in[0] > domain[0][1]) { x = domain[0][1]; } else { x = in[0]; } for (i = 0; i < n; ++i) { out[i] = c0[i] + pow(x, e) * (c1[i] - c0[i]); if (hasRange) { if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { out[i] = range[i][1]; } } } return; } //------------------------------------------------------------------------ // StitchingFunction //------------------------------------------------------------------------ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict, int recursion) { Object obj1, obj2; int i; ok = gFalse; funcs = NULL; bounds = NULL; encode = NULL; scale = NULL; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (m != 1) { error(errSyntaxError, -1, "Stitching function with more than one input"); goto err1; } //----- Functions if (!dict->lookup("Functions", &obj1)->isArray()) { error(errSyntaxError, -1, "Missing 'Functions' entry in stitching function"); goto err1; } k = obj1.arrayGetLength(); funcs = (Function **)gmallocn(k, sizeof(Function *)); bounds = (double *)gmallocn(k + 1, sizeof(double)); encode = (double *)gmallocn(2 * k, sizeof(double)); scale = (double *)gmallocn(k, sizeof(double)); for (i = 0; i < k; ++i) { funcs[i] = NULL; } for (i = 0; i < k; ++i) { if (!(funcs[i] = Function::parse(obj1.arrayGet(i, &obj2), recursion + 1))) { goto err2; } if (funcs[i]->getInputSize() != 1 || (i > 0 && funcs[i]->getOutputSize() != funcs[0]->getOutputSize())) { error(errSyntaxError, -1, "Incompatible subfunctions in stitching function"); goto err2; } obj2.free(); } obj1.free(); //----- Bounds if (!dict->lookup("Bounds", &obj1)->isArray() || obj1.arrayGetLength() != k - 1) { error(errSyntaxError, -1, "Missing or invalid 'Bounds' entry in stitching function"); goto err1; } bounds[0] = domain[0][0]; for (i = 1; i < k; ++i) { if (!obj1.arrayGet(i - 1, &obj2)->isNum()) { error(errSyntaxError, -1, "Invalid type in 'Bounds' array in stitching function"); goto err2; } bounds[i] = obj2.getNum(); obj2.free(); } bounds[k] = domain[0][1]; obj1.free(); //----- Encode if (!dict->lookup("Encode", &obj1)->isArray() || obj1.arrayGetLength() != 2 * k) { error(errSyntaxError, -1, "Missing or invalid 'Encode' entry in stitching function"); goto err1; } for (i = 0; i < 2 * k; ++i) { if (!obj1.arrayGet(i, &obj2)->isNum()) { error(errSyntaxError, -1, "Invalid type in 'Encode' array in stitching function"); goto err2; } encode[i] = obj2.getNum(); obj2.free(); } obj1.free(); //----- pre-compute the scale factors for (i = 0; i < k; ++i) { if (bounds[i] == bounds[i+1]) { // avoid a divide-by-zero -- in this situation, function i will // never be used anyway scale[i] = 0; } else { scale[i] = (encode[2*i+1] - encode[2*i]) / (bounds[i+1] - bounds[i]); } } ok = gTrue; return; err2: obj2.free(); err1: obj1.free(); } StitchingFunction::StitchingFunction(StitchingFunction *func) { int i; memcpy(this, func, sizeof(StitchingFunction)); funcs = (Function **)gmallocn(k, sizeof(Function *)); for (i = 0; i < k; ++i) { funcs[i] = func->funcs[i]->copy(); } bounds = (double *)gmallocn(k + 1, sizeof(double)); memcpy(bounds, func->bounds, (k + 1) * sizeof(double)); encode = (double *)gmallocn(2 * k, sizeof(double)); memcpy(encode, func->encode, 2 * k * sizeof(double)); scale = (double *)gmallocn(k, sizeof(double)); memcpy(scale, func->scale, k * sizeof(double)); ok = gTrue; } StitchingFunction::~StitchingFunction() { int i; if (funcs) { for (i = 0; i < k; ++i) { if (funcs[i]) { delete funcs[i]; } } } gfree(funcs); gfree(bounds); gfree(encode); gfree(scale); } void StitchingFunction::transform(double *in, double *out) { double x; int i; if (in[0] < domain[0][0]) { x = domain[0][0]; } else if (in[0] > domain[0][1]) { x = domain[0][1]; } else { x = in[0]; } for (i = 0; i < k - 1; ++i) { if (x < bounds[i+1]) { break; } } x = encode[2*i] + (x - bounds[i]) * scale[i]; funcs[i]->transform(&x, out); } //------------------------------------------------------------------------ // PostScriptFunction //------------------------------------------------------------------------ enum PSOp { psOpAbs, psOpAdd, psOpAnd, psOpAtan, psOpBitshift, psOpCeiling, psOpCopy, psOpCos, psOpCvi, psOpCvr, psOpDiv, psOpDup, psOpEq, psOpExch, psOpExp, psOpFalse, psOpFloor, psOpGe, psOpGt, psOpIdiv, psOpIndex, psOpLe, psOpLn, psOpLog, psOpLt, psOpMod, psOpMul, psOpNe, psOpNeg, psOpNot, psOpOr, psOpPop, psOpRoll, psOpRound, psOpSin, psOpSqrt, psOpSub, psOpTrue, psOpTruncate, psOpXor, psOpIf, psOpIfelse, psOpReturn }; // Note: 'if' and 'ifelse' are parsed separately. // The rest are listed here in alphabetical order. // The index in this table is equivalent to the entry in PSOp. static const char *psOpNames[] = { "abs", "add", "and", "atan", "bitshift", "ceiling", "copy", "cos", "cvi", "cvr", "div", "dup", "eq", "exch", "exp", "false", "floor", "ge", "gt", "idiv", "index", "le", "ln", "log", "lt", "mod", "mul", "ne", "neg", "not", "or", "pop", "roll", "round", "sin", "sqrt", "sub", "true", "truncate", "xor" }; #define nPSOps (sizeof(psOpNames) / sizeof(char *)) enum PSObjectType { psBool, psInt, psReal, psOperator, psBlock }; // In the code array, 'if'/'ifelse' operators take up three slots // plus space for the code in the subclause(s). // // +---------------------------------+ // | psOperator: psOpIf / psOpIfelse | // +---------------------------------+ // | psBlock: ptr= | // +---------------------------------+ // | psBlock: ptr= | // +---------------------------------+ // | if clause | // | ... | // | psOperator: psOpReturn | // +---------------------------------+ // | else clause | // | ... | // | psOperator: psOpReturn | // +---------------------------------+ // | ... | // // For 'if', pointer is present in the code stream but unused. struct PSObject { PSObjectType type; union { GBool booln; // boolean (stack only) int intg; // integer (stack and code) double real; // real (stack and code) PSOp op; // operator (code only) int blk; // if/ifelse block pointer (code only) }; }; #define psStackSize 100 class PSStack { public: PSStack() { sp = psStackSize; } void pushBool(GBool booln); void pushInt(int intg); void pushReal(double real); GBool popBool(); int popInt(); double popNum(); GBool empty() { return sp == psStackSize; } GBool topIsInt() { return sp < psStackSize && stack[sp].type == psInt; } GBool topTwoAreInts() { return sp < psStackSize - 1 && stack[sp].type == psInt && stack[sp+1].type == psInt; } GBool topIsReal() { return sp < psStackSize && stack[sp].type == psReal; } GBool topTwoAreNums() { return sp < psStackSize - 1 && (stack[sp].type == psInt || stack[sp].type == psReal) && (stack[sp+1].type == psInt || stack[sp+1].type == psReal); } void copy(int n); void roll(int n, int j); void index(int i); void pop(); private: GBool checkOverflow(int n = 1); GBool checkUnderflow(); GBool checkType(PSObjectType t1, PSObjectType t2); PSObject stack[psStackSize]; int sp; }; GBool PSStack::checkOverflow(int n) { if (sp - n < 0) { error(errSyntaxError, -1, "Stack overflow in PostScript function"); return gFalse; } return gTrue; } GBool PSStack::checkUnderflow() { if (sp == psStackSize) { error(errSyntaxError, -1, "Stack underflow in PostScript function"); return gFalse; } return gTrue; } GBool PSStack::checkType(PSObjectType t1, PSObjectType t2) { if (stack[sp].type != t1 && stack[sp].type != t2) { error(errSyntaxError, -1, "Type mismatch in PostScript function"); return gFalse; } return gTrue; } void PSStack::pushBool(GBool booln) { if (checkOverflow()) { stack[--sp].type = psBool; stack[sp].booln = booln; } } void PSStack::pushInt(int intg) { if (checkOverflow()) { stack[--sp].type = psInt; stack[sp].intg = intg; } } void PSStack::pushReal(double real) { if (checkOverflow()) { stack[--sp].type = psReal; stack[sp].real = real; } } GBool PSStack::popBool() { if (checkUnderflow() && checkType(psBool, psBool)) { return stack[sp++].booln; } return gFalse; } int PSStack::popInt() { if (checkUnderflow() && checkType(psInt, psInt)) { return stack[sp++].intg; } return 0; } double PSStack::popNum() { double ret; if (checkUnderflow() && checkType(psInt, psReal)) { ret = (stack[sp].type == psInt) ? (double)stack[sp].intg : stack[sp].real; ++sp; return ret; } return 0; } void PSStack::copy(int n) { int i; if (sp + n > psStackSize) { error(errSyntaxError, -1, "Stack underflow in PostScript function"); return; } if (!checkOverflow(n)) { return; } for (i = sp + n - 1; i >= sp; --i) { stack[i - n] = stack[i]; } sp -= n; } void PSStack::roll(int n, int j) { PSObject obj; int i, k; if (j >= 0) { j %= n; } else { j = -j % n; if (j != 0) { j = n - j; } } if (n <= 0 || j == 0 || n > psStackSize || sp + n > psStackSize) { return; } for (i = 0; i < j; ++i) { obj = stack[sp]; for (k = sp; k < sp + n - 1; ++k) { stack[k] = stack[k+1]; } stack[sp + n - 1] = obj; } } void PSStack::index(int i) { if (!checkOverflow()) { return; } --sp; stack[sp] = stack[sp + 1 + i]; } void PSStack::pop() { if (!checkUnderflow()) { return; } ++sp; } PostScriptFunction::PostScriptFunction(Object *funcObj, Dict *dict) { Stream *str; int codePtr; GString *tok; double in[funcMaxInputs]; int i; codeString = NULL; code = NULL; codeSize = 0; ok = gFalse; //----- initialize the generic stuff if (!init(dict)) { goto err1; } if (!hasRange) { error(errSyntaxError, -1, "Type 4 function is missing range"); goto err1; } //----- get the stream if (!funcObj->isStream()) { error(errSyntaxError, -1, "Type 4 function isn't a stream"); goto err1; } str = funcObj->getStream(); //----- parse the function codeString = new GString(); str->reset(); if (!(tok = getToken(str)) || tok->cmp("{")) { error(errSyntaxError, -1, "Expected '{' at start of PostScript function"); if (tok) { delete tok; } goto err1; } delete tok; codePtr = 0; if (!parseCode(str, &codePtr)) { goto err2; } str->close(); //----- set up the cache for (i = 0; i < m; ++i) { in[i] = domain[i][0]; cacheIn[i] = in[i] - 1; } transform(in, cacheOut); ok = gTrue; err2: str->close(); err1: return; } PostScriptFunction::PostScriptFunction(PostScriptFunction *func) { memcpy(this, func, sizeof(PostScriptFunction)); code = (PSObject *)gmallocn(codeSize, sizeof(PSObject)); memcpy(code, func->code, codeSize * sizeof(PSObject)); codeString = func->codeString->copy(); } PostScriptFunction::~PostScriptFunction() { gfree(code); if (codeString) { delete codeString; } } void PostScriptFunction::transform(double *in, double *out) { PSStack *stack; int i; // check the cache for (i = 0; i < m; ++i) { if (in[i] != cacheIn[i]) { break; } } if (i == m) { for (i = 0; i < n; ++i) { out[i] = cacheOut[i]; } return; } stack = new PSStack(); for (i = 0; i < m; ++i) { //~ may need to check for integers here stack->pushReal(in[i]); } exec(stack, 0); for (i = n - 1; i >= 0; --i) { out[i] = stack->popNum(); if (out[i] < range[i][0]) { out[i] = range[i][0]; } else if (out[i] > range[i][1]) { out[i] = range[i][1]; } } // if (!stack->empty()) { // error(errSyntaxWarning, -1, // "Extra values on stack at end of PostScript function"); // } delete stack; // save current result in the cache for (i = 0; i < m; ++i) { cacheIn[i] = in[i]; } for (i = 0; i < n; ++i) { cacheOut[i] = out[i]; } } GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { GString *tok; char *p; GBool isReal; int opPtr, elsePtr; int a, b, mid, cmp; while (1) { if (!(tok = getToken(str))) { error(errSyntaxError, -1, "Unexpected end of PostScript function stream"); return gFalse; } p = tok->getCString(); if (isdigit(*p) || *p == '.' || *p == '-') { isReal = gFalse; for (; *p; ++p) { if (*p == '.') { isReal = gTrue; break; } } resizeCode(*codePtr); if (isReal) { code[*codePtr].type = psReal; code[*codePtr].real = atof(tok->getCString()); } else { code[*codePtr].type = psInt; code[*codePtr].intg = atoi(tok->getCString()); } ++*codePtr; delete tok; } else if (!tok->cmp("{")) { delete tok; opPtr = *codePtr; *codePtr += 3; resizeCode(opPtr + 2); if (!parseCode(str, codePtr)) { return gFalse; } if (!(tok = getToken(str))) { error(errSyntaxError, -1, "Unexpected end of PostScript function stream"); return gFalse; } if (!tok->cmp("{")) { elsePtr = *codePtr; if (!parseCode(str, codePtr)) { return gFalse; } delete tok; if (!(tok = getToken(str))) { error(errSyntaxError, -1, "Unexpected end of PostScript function stream"); return gFalse; } } else { elsePtr = -1; } if (!tok->cmp("if")) { if (elsePtr >= 0) { error(errSyntaxError, -1, "Got 'if' operator with two blocks in PostScript function"); return gFalse; } code[opPtr].type = psOperator; code[opPtr].op = psOpIf; code[opPtr+2].type = psBlock; code[opPtr+2].blk = *codePtr; } else if (!tok->cmp("ifelse")) { if (elsePtr < 0) { error(errSyntaxError, -1, "Got 'ifelse' operator with one block in PostScript function"); return gFalse; } code[opPtr].type = psOperator; code[opPtr].op = psOpIfelse; code[opPtr+1].type = psBlock; code[opPtr+1].blk = elsePtr; code[opPtr+2].type = psBlock; code[opPtr+2].blk = *codePtr; } else { error(errSyntaxError, -1, "Expected if/ifelse operator in PostScript function"); delete tok; return gFalse; } delete tok; } else if (!tok->cmp("}")) { delete tok; resizeCode(*codePtr); code[*codePtr].type = psOperator; code[*codePtr].op = psOpReturn; ++*codePtr; break; } else { a = -1; b = nPSOps; cmp = 0; // make gcc happy // invariant: psOpNames[a] < tok < psOpNames[b] while (b - a > 1) { mid = (a + b) / 2; cmp = tok->cmp(psOpNames[mid]); if (cmp > 0) { a = mid; } else if (cmp < 0) { b = mid; } else { a = b = mid; } } if (cmp != 0) { error(errSyntaxError, -1, "Unknown operator '{0:t}' in PostScript function", tok); delete tok; return gFalse; } delete tok; resizeCode(*codePtr); code[*codePtr].type = psOperator; code[*codePtr].op = (PSOp)a; ++*codePtr; } } return gTrue; } GString *PostScriptFunction::getToken(Stream *str) { GString *s; int c; GBool comment; s = new GString(); comment = gFalse; while (1) { if ((c = str->getChar()) == EOF) { break; } codeString->append(c); if (comment) { if (c == '\x0a' || c == '\x0d') { comment = gFalse; } } else if (c == '%') { comment = gTrue; } else if (!isspace(c)) { break; } } if (c == '{' || c == '}') { s->append((char)c); } else if (isdigit(c) || c == '.' || c == '-') { while (1) { s->append((char)c); c = str->lookChar(); if (c == EOF || !(isdigit(c) || c == '.' || c == '-')) { break; } str->getChar(); codeString->append(c); } } else { while (1) { s->append((char)c); c = str->lookChar(); if (c == EOF || !isalnum(c)) { break; } str->getChar(); codeString->append(c); } } return s; } void PostScriptFunction::resizeCode(int newSize) { if (newSize >= codeSize) { codeSize += 64; code = (PSObject *)greallocn(code, codeSize, sizeof(PSObject)); } } void PostScriptFunction::exec(PSStack *stack, int codePtr) { int i1, i2; double r1, r2; GBool b1, b2; while (1) { switch (code[codePtr].type) { case psInt: stack->pushInt(code[codePtr++].intg); break; case psReal: stack->pushReal(code[codePtr++].real); break; case psOperator: switch (code[codePtr++].op) { case psOpAbs: if (stack->topIsInt()) { stack->pushInt(abs(stack->popInt())); } else { stack->pushReal(fabs(stack->popNum())); } break; case psOpAdd: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 + i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(r1 + r2); } break; case psOpAnd: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 & i2); } else { b2 = stack->popBool(); b1 = stack->popBool(); stack->pushBool(b1 && b2); } break; case psOpAtan: r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(atan2(r1, r2)); break; case psOpBitshift: i2 = stack->popInt(); i1 = stack->popInt(); if (i2 > 0) { stack->pushInt(i1 << i2); } else if (i2 < 0) { stack->pushInt((int)((Guint)i1 >> -i2)); } else { stack->pushInt(i1); } break; case psOpCeiling: if (!stack->topIsInt()) { stack->pushReal(ceil(stack->popNum())); } break; case psOpCopy: stack->copy(stack->popInt()); break; case psOpCos: stack->pushReal(cos(stack->popNum())); break; case psOpCvi: if (!stack->topIsInt()) { stack->pushInt((int)stack->popNum()); } break; case psOpCvr: if (!stack->topIsReal()) { stack->pushReal(stack->popNum()); } break; case psOpDiv: r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(r1 / r2); break; case psOpDup: stack->copy(1); break; case psOpEq: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 == i2); } else if (stack->topTwoAreNums()) { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 == r2); } else { b2 = stack->popBool(); b1 = stack->popBool(); stack->pushBool(b1 == b2); } break; case psOpExch: stack->roll(2, 1); break; case psOpExp: r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(pow(r1, r2)); break; case psOpFalse: stack->pushBool(gFalse); break; case psOpFloor: if (!stack->topIsInt()) { stack->pushReal(floor(stack->popNum())); } break; case psOpGe: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 >= i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 >= r2); } break; case psOpGt: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 > i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 > r2); } break; case psOpIdiv: i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 / i2); break; case psOpIndex: stack->index(stack->popInt()); break; case psOpLe: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 <= i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 <= r2); } break; case psOpLn: stack->pushReal(log(stack->popNum())); break; case psOpLog: stack->pushReal(log10(stack->popNum())); break; case psOpLt: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 < i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 < r2); } break; case psOpMod: i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 % i2); break; case psOpMul: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); //~ should check for out-of-range, and push a real instead stack->pushInt(i1 * i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(r1 * r2); } break; case psOpNe: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushBool(i1 != i2); } else if (stack->topTwoAreNums()) { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushBool(r1 != r2); } else { b2 = stack->popBool(); b1 = stack->popBool(); stack->pushBool(b1 != b2); } break; case psOpNeg: if (stack->topIsInt()) { stack->pushInt(-stack->popInt()); } else { stack->pushReal(-stack->popNum()); } break; case psOpNot: if (stack->topIsInt()) { stack->pushInt(~stack->popInt()); } else { stack->pushBool(!stack->popBool()); } break; case psOpOr: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 | i2); } else { b2 = stack->popBool(); b1 = stack->popBool(); stack->pushBool(b1 || b2); } break; case psOpPop: stack->pop(); break; case psOpRoll: i2 = stack->popInt(); i1 = stack->popInt(); stack->roll(i1, i2); break; case psOpRound: if (!stack->topIsInt()) { r1 = stack->popNum(); stack->pushReal((r1 >= 0) ? floor(r1 + 0.5) : ceil(r1 - 0.5)); } break; case psOpSin: stack->pushReal(sin(stack->popNum())); break; case psOpSqrt: stack->pushReal(sqrt(stack->popNum())); break; case psOpSub: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 - i2); } else { r2 = stack->popNum(); r1 = stack->popNum(); stack->pushReal(r1 - r2); } break; case psOpTrue: stack->pushBool(gTrue); break; case psOpTruncate: if (!stack->topIsInt()) { r1 = stack->popNum(); stack->pushReal((r1 >= 0) ? floor(r1) : ceil(r1)); } break; case psOpXor: if (stack->topTwoAreInts()) { i2 = stack->popInt(); i1 = stack->popInt(); stack->pushInt(i1 ^ i2); } else { b2 = stack->popBool(); b1 = stack->popBool(); stack->pushBool(b1 ^ b2); } break; case psOpIf: b1 = stack->popBool(); if (b1) { exec(stack, codePtr + 2); } codePtr = code[codePtr + 1].blk; break; case psOpIfelse: b1 = stack->popBool(); if (b1) { exec(stack, codePtr + 2); } else { exec(stack, code[codePtr].blk); } codePtr = code[codePtr + 1].blk; break; case psOpReturn: return; } break; default: error(errSyntaxError, -1, "Internal: bad object in PostScript function code"); break; } } } xpdf-3.03/xpdf/about-text.h0000644000076400007640000000131611622305345015122 0ustar dereknderekn//======================================================================== // // about-text.h // // Copyright 2002-2007 Glyph & Cog, LLC // //======================================================================== static const char *aboutWinText[] = { "http://www.foolabs.com/xpdf/", "derekn@foolabs.com", " ", "Licensed under the GNU General Public License (GPL) v2 or v3.", "See the 'README' file for details.", " ", "Supports PDF version " supportedPDFVersionStr ".", " ", "The PDF data structures, operators, and specification", "are copyright 1985-2006 Adobe Systems Inc.", " ", "For more information (including key and mouse bindings)", "please read the xpdf(1) man page.", NULL }; xpdf-3.03/xpdf/FontEncodingTables.h0000644000076400007640000000106411622305345016536 0ustar dereknderekn//======================================================================== // // FontEncodingTables.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FONTENCODINGTABLES_H #define FONTENCODINGTABLES_H extern const char *macRomanEncoding[]; extern const char *macExpertEncoding[]; extern const char *winAnsiEncoding[]; extern const char *standardEncoding[]; extern const char *expertEncoding[]; extern const char *symbolEncoding[]; extern const char *zapfDingbatsEncoding[]; #endif xpdf-3.03/xpdf/XPDFTreeP.h0000644000076400007640000000432311622305345014530 0ustar dereknderekn//======================================================================== // // XPDFTreeP.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef XPDFTREEP_H #define XPDFTREEP_H #include #include #include "XPDFTree.h" extern "C" { typedef void (*XPDFLayoutProc)(Widget widget, Widget instigator); typedef void (*XPDFCalcSizeProc)(Widget widget, Widget instigator, Dimension *totalWidth, Dimension *totalHeight); typedef Boolean (*XPDFNeedRelayoutProc)(Widget oldWidget, Widget newWidget); #define XPDFInheritCreateGC ((XtWidgetProc)_XtInherit) #define XPDFInheritDestroyGC ((XtWidgetProc)_XtInherit) #define XPDFInheritLayout ((XPDFLayoutProc)_XtInherit) #define XPDFInheritCalcSize ((XPDFCalcSizeProc)_XtInherit) #define XPDFInheritNeedRelayout ((XPDFNeedRelayoutProc)_XtInherit) typedef struct { XtWidgetProc createGC; XtWidgetProc destroyGC; XPDFLayoutProc layout; XPDFCalcSizeProc calcSize; XPDFNeedRelayoutProc needRelayout; XtPointer extension; } XPDFTreeClassPart; typedef struct _XPDFTreeClassRec { CoreClassPart coreClass; CompositeClassPart compositeClass; ConstraintClassPart constraintClass; XmManagerClassPart managerClass; XPDFTreeClassPart treeClass; } XPDFTreeClassRec; externalref XPDFTreeClassRec xpdfTreeClassRec; typedef struct _XPDFTreeEntry XPDFTreeEntry; typedef struct { Dimension marginWidth; Dimension marginHeight; XtCallbackList selectCallback; GC plainGC; GC dottedGC; XPDFTreeEntry *root; int redrawY; } XPDFTreePart; typedef struct _XPDFTreeRec { CorePart core; CompositePart composite; ConstraintPart constraint; XmManagerPart manager; XPDFTreePart tree; } XPDFTreeRec; #define XPDFTreeIndex (XmManagerIndex + 1) typedef struct _XPDFTreeConstraintPart { Widget entryParent; Boolean entryExpanded; int entryPosition; XPDFTreeEntry *e; } XPDFTreeConstraintPart, *XPDFTreeConstraint; typedef struct _XPDFTreeConstraintRec { XmManagerConstraintPart manager; XPDFTreeConstraintPart tree; } XPDFTreeConstraintRec, *XPDFTreeConstraintPtr; #define XPDFTreeCPart(w) \ (&((XPDFTreeConstraintPtr)(w)->core.constraints)->tree) } // extern "C" #endif xpdf-3.03/xpdf/Makefile.in0000644000076400007640000002355611622305345014734 0ustar dereknderekn#======================================================================== # # Xpdf Makefile # # Copyright 1996-2003 Glyph & Cog, LLC # #======================================================================== SHELL = /bin/sh prefix = @prefix@ srcdir = @srcdir@ VPATH = @srcdir@ GOOSRCDIR = $(srcdir)/../goo GOOLIBDIR = ../goo FOFISRCDIR = $(srcdir)/../fofi FOFILIBDIR = ../fofi SPLASHSRCDIR = $(srcdir)/../splash SPLASHLIBDIR = ../splash CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(SPLASHSRCDIR) -I$(srcdir) @freetype2_CFLAGS@ @Sgm_CFLAGS@ @Xm_CFLAGS@ @Xt_CFLAGS@ @Xp_CFLAGS@ @Xext_CFLAGS@ @Xpm_CFLAGS@ @t1_CFLAGS@ @libpaper_CFLAGS@ @X_CFLAGS@ LDFLAGS = @LDFLAGS@ T1LIBS = @t1_LIBS@ FTLIBS = @freetype2_LIBS@ XLIBS = @Sgm_LIBS@ @Xm_LIBS@ @Xt_LIBS@ @Xp_LIBS@ @Xext_LIBS@ @Xpm_LIBS@ @X_PRE_LIBS@ @X_LIBS@ -lX11 @X_EXTRA_LIBS@ SPLASHLIBS = -L$(SPLASHLIBDIR) -lsplash OTHERLIBS = @LIBS@ @libpaper_LIBS@ \ -L$(FOFILIBDIR) -lfofi \ -L$(GOOLIBDIR) -lGoo CXX = @CXX@ LIBPREFIX = @LIBPREFIX@ EXE = @EXE@ #------------------------------------------------------------------------ .SUFFIXES: .cc .cc.o: $(CXX) $(CXXFLAGS) -c $< #------------------------------------------------------------------------ CXX_SRC = \ $(srcdir)/Annot.cc \ $(srcdir)/Array.cc \ $(srcdir)/BuiltinFont.cc \ $(srcdir)/BuiltinFontTables.cc \ $(srcdir)/CMap.cc \ $(srcdir)/Catalog.cc \ $(srcdir)/CharCodeToUnicode.cc \ $(srcdir)/CoreOutputDev.cc \ $(srcdir)/Decrypt.cc \ $(srcdir)/Dict.cc \ $(srcdir)/Error.cc \ $(srcdir)/FontEncodingTables.cc \ $(srcdir)/Function.cc \ $(srcdir)/Gfx.cc \ $(srcdir)/GfxFont.cc \ $(srcdir)/GfxState.cc \ $(srcdir)/GlobalParams.cc \ $(srcdir)/ImageOutputDev.cc \ $(srcdir)/JArithmeticDecoder.cc \ $(srcdir)/JBIG2Stream.cc \ $(srcdir)/JPXStream.cc \ $(srcdir)/Lexer.cc \ $(srcdir)/Link.cc \ $(srcdir)/NameToCharCode.cc \ $(srcdir)/Object.cc \ $(srcdir)/OptionalContent.cc \ $(srcdir)/Outline.cc \ $(srcdir)/OutputDev.cc \ $(srcdir)/PDFCore.cc \ $(srcdir)/PDFDoc.cc \ $(srcdir)/PDFDocEncoding.cc \ $(srcdir)/PSOutputDev.cc \ $(srcdir)/PSTokenizer.cc \ $(srcdir)/Page.cc \ $(srcdir)/Parser.cc \ $(srcdir)/PreScanOutputDev.cc \ $(srcdir)/SecurityHandler.cc \ $(srcdir)/SplashOutputDev.cc \ $(srcdir)/Stream.cc \ $(srcdir)/TextOutputDev.cc \ $(srcdir)/UnicodeMap.cc \ $(srcdir)/UnicodeTypeTable.cc \ $(srcdir)/XPDFApp.cc \ $(srcdir)/XPDFCore.cc \ $(srcdir)/XPDFTree.cc \ $(srcdir)/XPDFViewer.cc \ $(srcdir)/XpdfPluginAPI.cc \ $(srcdir)/XRef.cc \ $(srcdir)/pdftops.cc \ $(srcdir)/pdftotext.cc \ $(srcdir)/pdfinfo.cc \ $(srcdir)/pdffonts.cc \ $(srcdir)/pdfdetach.cc \ $(srcdir)/pdftoppm.cc \ $(srcdir)/pdfimages.cc \ $(srcdir)/xpdf.cc #------------------------------------------------------------------------ all: xpdf$(EXE) pdftops$(EXE) pdftotext$(EXE) pdfinfo$(EXE) \ pdffonts$(EXE) pdfdetach$(EXE) pdftoppm$(EXE) pdfimages$(EXE) all-no-x: pdftops$(EXE) pdftotext$(EXE) pdfinfo$(EXE) pdffonts$(EXE) \ pdfdetach$(EXE) pdfimages$(EXE) #------------------------------------------------------------------------ XPDF_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o Catalog.o \ CharCodeToUnicode.o CMap.o CoreOutputDev.o Decrypt.o Dict.o \ Error.o FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFCore.o \ PDFDoc.o PDFDocEncoding.o PreScanOutputDev.o PSOutputDev.o \ PSTokenizer.o SecurityHandler.o SplashOutputDev.o Stream.o \ TextOutputDev.o UnicodeMap.o UnicodeTypeTable.o XPDFApp.o \ XPDFCore.o XPDFTree.o XPDFViewer.o XpdfPluginAPI.o XRef.o xpdf.o XPDF_LIBS = -L$(GOOLIBDIR) -lGoo $(SPLASHLIBS) $(T1LIBS) $(FTLIBS) \ $(XLIBS) $(OTHERLIBS) -lm xpdf$(EXE): $(XPDF_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o xpdf$(EXE) $(XPDF_OBJS) $(XPDF_LIBS) #------------------------------------------------------------------------ PDFTOPS_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o OptionalContent.o \ Outline.o Object.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PreScanOutputDev.o PSOutputDev.o PSTokenizer.o \ SecurityHandler.o SplashOutputDev.o Stream.o UnicodeMap.o \ XpdfPluginAPI.o XRef.o pdftops.o PDFTOPS_LIBS = -L$(GOOLIBDIR) -lGoo $(SPLASHLIBS) $(T1LIBS) $(FTLIBS) \ $(OTHERLIBS) -lm pdftops$(EXE): $(PDFTOPS_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdftops$(EXE) $(PDFTOPS_OBJS) \ $(PDFTOPS_LIBS) #------------------------------------------------------------------------ PDFTOTEXT_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PSTokenizer.o SecurityHandler.o Stream.o \ TextOutputDev.o UnicodeMap.o UnicodeTypeTable.o XpdfPluginAPI.o \ XRef.o pdftotext.o PDFTOTEXT_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdftotext$(EXE): $(PDFTOTEXT_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdftotext$(EXE) $(PDFTOTEXT_OBJS) \ $(PDFTOTEXT_LIBS) #------------------------------------------------------------------------ PDFINFO_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PSTokenizer.o SecurityHandler.o Stream.o \ UnicodeMap.o XpdfPluginAPI.o XRef.o pdfinfo.o PDFINFO_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfinfo$(EXE): $(PDFINFO_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdfinfo$(EXE) $(PDFINFO_OBJS) \ $(PDFINFO_LIBS) #------------------------------------------------------------------------ PDFFONTS_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PSTokenizer.o SecurityHandler.o Stream.o \ UnicodeMap.o XpdfPluginAPI.o XRef.o pdffonts.o PDFFONTS_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdffonts$(EXE): $(PDFFONTS_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdffonts$(EXE) $(PDFFONTS_OBJS) \ $(PDFFONTS_LIBS) #------------------------------------------------------------------------ PDFDETACH_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o \ GfxState.o GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o \ JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PSTokenizer.o SecurityHandler.o Stream.o \ UnicodeMap.o XpdfPluginAPI.o XRef.o pdfdetach.o PDFDETACH_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfdetach$(EXE): $(PDFDETACH_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdfdetach$(EXE) $(PDFDETACH_OBJS) \ $(PDFDETACH_LIBS) #------------------------------------------------------------------------ PDFTOPPM_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o GfxState.o \ GlobalParams.o JArithmeticDecoder.o JBIG2Stream.o JPXStream.o \ Lexer.o Link.o NameToCharCode.o Object.o OptionalContent.o \ Outline.o OutputDev.o Page.o Parser.o PDFDoc.o PDFDocEncoding.o \ PSTokenizer.o SecurityHandler.o SplashOutputDev.o Stream.o \ TextOutputDev.o UnicodeMap.o UnicodeTypeTable.o XpdfPluginAPI.o \ XRef.o pdftoppm.o PDFTOPPM_LIBS = -L$(GOOLIBDIR) -lGoo $(SPLASHLIBS) $(T1LIBS) $(FTLIBS) \ $(OTHERLIBS) -lm pdftoppm$(EXE): $(PDFTOPPM_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdftoppm$(EXE) $(PDFTOPPM_OBJS) \ $(PDFTOPPM_LIBS) #------------------------------------------------------------------------ PDFIMAGES_OBJS = Annot.o Array.o BuiltinFont.o BuiltinFontTables.o \ Catalog.o CharCodeToUnicode.o CMap.o Decrypt.o Dict.o Error.o \ FontEncodingTables.o Function.o Gfx.o GfxFont.o GfxState.o \ GlobalParams.o ImageOutputDev.o JArithmeticDecoder.o \ JBIG2Stream.o JPXStream.o Lexer.o Link.o NameToCharCode.o Object.o \ OptionalContent.o Outline.o OutputDev.o Page.o Parser.o PDFDoc.o \ PDFDocEncoding.o PSTokenizer.o SecurityHandler.o Stream.o \ UnicodeMap.o XpdfPluginAPI.o XRef.o pdfimages.o PDFIMAGES_LIBS = -L$(GOOLIBDIR) -lGoo $(OTHERLIBS) -lm pdfimages$(EXE): $(PDFIMAGES_OBJS) $(GOOLIBDIR)/$(LIBPREFIX)Goo.a $(CXX) $(CXXFLAGS) $(LDFLAGS) -o pdfimages$(EXE) $(PDFIMAGES_OBJS) \ $(PDFIMAGES_LIBS) #------------------------------------------------------------------------ clean: rm -f $(XPDF_OBJS) xpdf$(EXE) rm -f $(PDFTOPS_OBJS) pdftops$(EXE) rm -f $(PDFTOTEXT_OBJS) pdftotext$(EXE) rm -f $(PDFINFO_OBJS) pdfinfo$(EXE) rm -f $(PDFFONTS_OBJS) pdffonts$(EXE) rm -f $(PDFDETACH_OBJS) pdfdetach$(EXE) rm -f $(PDFTOPPM_OBJS) pdftoppm$(EXE) rm -f $(PDFIMAGES_OBJS) pdfimages$(EXE) #------------------------------------------------------------------------ depend: $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep include Makefile.dep xpdf-3.03/xpdf/PDFDoc.cc0000644000076400007640000003114211622305345014223 0ustar dereknderekn//======================================================================== // // PDFDoc.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #ifdef WIN32 # include #endif #include "GString.h" #include "config.h" #include "GlobalParams.h" #include "Page.h" #include "Catalog.h" #include "Stream.h" #include "XRef.h" #include "Link.h" #include "OutputDev.h" #include "Error.h" #include "ErrorCodes.h" #include "Lexer.h" #include "Parser.h" #include "SecurityHandler.h" #ifndef DISABLE_OUTLINE #include "Outline.h" #endif #include "OptionalContent.h" #include "PDFDoc.h" //------------------------------------------------------------------------ #define headerSearchSize 1024 // read this many bytes at beginning of // file to look for '%PDF' //------------------------------------------------------------------------ // PDFDoc //------------------------------------------------------------------------ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, GString *userPassword, PDFCore *coreA) { Object obj; GString *fileName1, *fileName2; #ifdef WIN32 int n, i; #endif ok = gFalse; errCode = errNone; core = coreA; file = NULL; str = NULL; xref = NULL; catalog = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif optContent = NULL; fileName = fileNameA; #ifdef WIN32 n = fileName->getLength(); fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); for (i = 0; i < n; ++i) { fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); } fileNameU[n] = L'\0'; #endif fileName1 = fileName; // try to open file fileName2 = NULL; #ifdef VMS if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName1); errCode = errOpenFile; return; } #else if (!(file = fopen(fileName1->getCString(), "rb"))) { fileName2 = fileName->copy(); fileName2->lowerCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { fileName2->upperCase(); if (!(file = fopen(fileName2->getCString(), "rb"))) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName); delete fileName2; errCode = errOpenFile; return; } } delete fileName2; } #endif // create stream obj.initNull(); str = new FileStream(file, 0, gFalse, 0, &obj); ok = setup(ownerPassword, userPassword); } #ifdef WIN32 PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, GString *userPassword, PDFCore *coreA) { OSVERSIONINFO version; Object obj; int i; ok = gFalse; errCode = errNone; core = coreA; file = NULL; str = NULL; xref = NULL; catalog = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif optContent = NULL; // save both Unicode and 8-bit copies of the file name fileName = new GString(); fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t)); for (i = 0; i < fileNameLen; ++i) { fileName->append((char)fileNameA[i]); fileNameU[i] = fileNameA[i]; } fileNameU[fileNameLen] = L'\0'; // try to open file // NB: _wfopen is only available in NT version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { file = _wfopen(fileNameU, L"rb"); } else { file = fopen(fileName->getCString(), "rb"); } if (!file) { error(errIO, -1, "Couldn't open file '{0:t}'", fileName); errCode = errOpenFile; return; } // create stream obj.initNull(); str = new FileStream(file, 0, gFalse, 0, &obj); ok = setup(ownerPassword, userPassword); } #endif PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, GString *userPassword, PDFCore *coreA) { #ifdef WIN32 int n, i; #endif ok = gFalse; errCode = errNone; core = coreA; if (strA->getFileName()) { fileName = strA->getFileName()->copy(); #ifdef WIN32 n = fileName->getLength(); fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); for (i = 0; i < n; ++i) { fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); } fileNameU[n] = L'\0'; #endif } else { fileName = NULL; #ifdef WIN32 fileNameU = NULL; #endif } file = NULL; str = strA; xref = NULL; catalog = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif optContent = NULL; ok = setup(ownerPassword, userPassword); } GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) { str->reset(); // check header checkHeader(); // read the xref and catalog if (!PDFDoc::setup2(ownerPassword, userPassword, gFalse)) { if (errCode == errDamaged || errCode == errBadCatalog) { // try repairing the xref table error(errSyntaxWarning, -1, "PDF file is damaged - attempting to reconstruct xref table..."); if (!PDFDoc::setup2(ownerPassword, userPassword, gTrue)) { return gFalse; } } else { return gFalse; } } #ifndef DISABLE_OUTLINE // read outline outline = new Outline(catalog->getOutline(), xref); #endif // read the optional content info optContent = new OptionalContent(this); // done return gTrue; } GBool PDFDoc::setup2(GString *ownerPassword, GString *userPassword, GBool repairXRef) { // read xref table xref = new XRef(str, repairXRef); if (!xref->isOk()) { error(errSyntaxError, -1, "Couldn't read xref table"); errCode = xref->getErrorCode(); delete xref; xref = NULL; return gFalse; } // check for encryption if (!checkEncryption(ownerPassword, userPassword)) { errCode = errEncrypted; delete xref; xref = NULL; return gFalse; } // read catalog catalog = new Catalog(this); if (!catalog->isOk()) { error(errSyntaxError, -1, "Couldn't read page catalog"); errCode = errBadCatalog; delete catalog; catalog = NULL; delete xref; xref = NULL; return gFalse; } return gTrue; } PDFDoc::~PDFDoc() { if (optContent) { delete optContent; } #ifndef DISABLE_OUTLINE if (outline) { delete outline; } #endif if (catalog) { delete catalog; } if (xref) { delete xref; } if (str) { delete str; } if (file) { fclose(file); } if (fileName) { delete fileName; } #ifdef WIN32 if (fileNameU) { gfree(fileNameU); } #endif } // Check for a PDF header on this stream. Skip past some garbage // if necessary. void PDFDoc::checkHeader() { char hdrBuf[headerSearchSize+1]; char *p; int i; pdfVersion = 0; for (i = 0; i < headerSearchSize; ++i) { hdrBuf[i] = str->getChar(); } hdrBuf[headerSearchSize] = '\0'; for (i = 0; i < headerSearchSize - 5; ++i) { if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { break; } } if (i >= headerSearchSize - 5) { error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); return; } str->moveStart(i); if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) { error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); return; } pdfVersion = atof(p); if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') || pdfVersion > supportedPDFVersionNum + 0.0001) { error(errSyntaxWarning, -1, "PDF version {0:s} -- xpdf supports version {1:s} (continuing anyway)", p, supportedPDFVersionStr); } } GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { Object encrypt; GBool encrypted; SecurityHandler *secHdlr; GBool ret; xref->getTrailerDict()->dictLookup("Encrypt", &encrypt); if ((encrypted = encrypt.isDict())) { if ((secHdlr = SecurityHandler::make(this, &encrypt))) { if (secHdlr->isUnencrypted()) { // no encryption ret = gTrue; } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) { // authorization succeeded xref->setEncryption(secHdlr->getPermissionFlags(), secHdlr->getOwnerPasswordOk(), secHdlr->getFileKey(), secHdlr->getFileKeyLength(), secHdlr->getEncVersion(), secHdlr->getEncAlgorithm()); ret = gTrue; } else { // authorization failed ret = gFalse; } delete secHdlr; } else { // couldn't find the matching security handler ret = gFalse; } } else { // document is not encrypted ret = gTrue; } encrypt.free(); return ret; } void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } catalog->getPage(page)->display(out, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData); } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { int page; for (page = firstPage; page <= lastPage; ++page) { displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData); catalog->doneWithPage(page); } } void PDFDoc::displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { catalog->getPage(page)->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData); } Links *PDFDoc::getLinks(int page) { return catalog->getPage(page)->getLinks(); } void PDFDoc::processLinks(OutputDev *out, int page) { catalog->getPage(page)->processLinks(out); } GBool PDFDoc::isLinearized() { Parser *parser; Object obj1, obj2, obj3, obj4, obj5; GBool lin; lin = gFalse; obj1.initNull(); parser = new Parser(xref, new Lexer(xref, str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), gTrue); parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); parser->getObj(&obj4); if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") && obj4.isDict()) { obj4.dictLookup("Linearized", &obj5); if (obj5.isNum() && obj5.getNum() > 0) { lin = gTrue; } obj5.free(); } obj4.free(); obj3.free(); obj2.free(); obj1.free(); delete parser; return lin; } GBool PDFDoc::saveAs(GString *name) { FILE *f; int c; if (!(f = fopen(name->getCString(), "wb"))) { error(errIO, -1, "Couldn't open file '{0:t}'", name); return gFalse; } str->reset(); while ((c = str->getChar()) != EOF) { fputc(c, f); } str->close(); fclose(f); return gTrue; } GBool PDFDoc::saveEmbeddedFile(int idx, char *path) { FILE *f; GBool ret; if (!(f = fopen(path, "wb"))) { return gFalse; } ret = saveEmbeddedFile2(idx, f); fclose(f); return ret; } #ifdef WIN32 GBool PDFDoc::saveEmbeddedFile(int idx, wchar_t *path, int pathLen) { FILE *f; OSVERSIONINFO version; wchar_t path2w[_MAX_PATH + 1]; char path2c[_MAX_PATH + 1]; int i; GBool ret; // NB: _wfopen is only available in NT version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { for (i = 0; i < pathLen && i < _MAX_PATH; ++i) { path2w[i] = path[i]; } path2w[i] = 0; f = _wfopen(path2w, L"wb"); } else { for (i = 0; i < pathLen && i < _MAX_PATH; ++i) { path2c[i] = (char)path[i]; } path2c[i] = 0; f = fopen(path2c, "wb"); } if (!f) { return gFalse; } ret = saveEmbeddedFile2(idx, f); fclose(f); return ret; } #endif GBool PDFDoc::saveEmbeddedFile2(int idx, FILE *f) { Object strObj; int c; if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) { return gFalse; } strObj.streamReset(); while ((c = strObj.streamGetChar()) != EOF) { fputc(c, f); } strObj.streamClose(); strObj.free(); return gTrue; } char *PDFDoc::getEmbeddedFileMem(int idx, int *size) { Object strObj; char *buf; int bufSize, len, c; if (!catalog->getEmbeddedFileStreamObj(idx, &strObj)) { return NULL; } strObj.streamReset(); bufSize = 1024; buf = (char *)gmalloc(bufSize); len = 0; while ((c = strObj.streamGetChar()) != EOF) { if (len == bufSize) { bufSize *= 2; buf = (char *)grealloc(buf, bufSize); } buf[len++] = (char)c; } strObj.streamClose(); strObj.free(); *size = len; return buf; } xpdf-3.03/xpdf/CoreOutputDev.h0000644000076400007640000000260111622305345015574 0ustar dereknderekn//======================================================================== // // CoreOutputDev.h // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #ifndef COREOUTPUTDEV_H #define COREOUTPUTDEV_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" #include "SplashOutputDev.h" class TextPage; //------------------------------------------------------------------------ typedef void (*CoreOutRedrawCbk)(void *data, int x0, int y0, int x1, int y1, GBool composited); //------------------------------------------------------------------------ // CoreOutputDev //------------------------------------------------------------------------ class CoreOutputDev: public SplashOutputDev { public: CoreOutputDev(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool incrementalUpdateA, CoreOutRedrawCbk redrawCbkA, void *redrawCbkDataA); virtual ~CoreOutputDev(); //----- initialization and control // End a page. virtual void endPage(); // Dump page contents to display. virtual void dump(); //----- special access // Clear out the document (used when displaying an empty window). void clear(); private: GBool incrementalUpdate; // incrementally update the display? CoreOutRedrawCbk redrawCbk; void *redrawCbkData; }; #endif xpdf-3.03/xpdf/UTF8.h0000644000076400007640000000242211622305345013553 0ustar dereknderekn//======================================================================== // // UTF8.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== static int mapUTF8(Unicode u, char *buf, int bufSize) { if (u <= 0x0000007f) { if (bufSize < 1) { return 0; } buf[0] = (char)u; return 1; } else if (u <= 0x000007ff) { if (bufSize < 2) { return 0; } buf[0] = (char)(0xc0 + (u >> 6)); buf[1] = (char)(0x80 + (u & 0x3f)); return 2; } else if (u <= 0x0000ffff) { if (bufSize < 3) { return 0; } buf[0] = (char)(0xe0 + (u >> 12)); buf[1] = (char)(0x80 + ((u >> 6) & 0x3f)); buf[2] = (char)(0x80 + (u & 0x3f)); return 3; } else if (u <= 0x0010ffff) { if (bufSize < 4) { return 0; } buf[0] = (char)(0xf0 + (u >> 18)); buf[1] = (char)(0x80 + ((u >> 12) & 0x3f)); buf[2] = (char)(0x80 + ((u >> 6) & 0x3f)); buf[3] = (char)(0x80 + (u & 0x3f)); return 4; } else { return 0; } } static int mapUCS2(Unicode u, char *buf, int bufSize) { if (u <= 0xffff) { if (bufSize < 2) { return 0; } buf[0] = (char)((u >> 8) & 0xff); buf[1] = (char)(u & 0xff); return 2; } else { return 0; } } xpdf-3.03/xpdf/XpdfPluginAPI.h0000644000076400007640000002332211622305345015441 0ustar dereknderekn/* * XpdfPluginAPI.h * * Copyright 2004 Glyph & Cog, LLC */ #ifndef XPDFPLUGINAPI_H #define XPDFPLUGINAPI_H #ifdef _WIN32 #include #else #define Object XtObject #include #undef Object #endif #ifdef __cplusplus extern "C" { #endif /*------------------------------------------------------------------------ * Macros *------------------------------------------------------------------------*/ /* * The current API version. */ #define xpdfPluginAPIVersion 1 #ifdef _WIN32 # ifdef __cplusplus # define PLUGINFUNC(retType) extern "C" __declspec(dllexport) retType # else # define PLUGINFUNC(retType) extern __declspec(dllexport) retType # endif #else # ifdef __cplusplus # define PLUGINFUNC(retType) extern "C" retType # else # define PLUGINFUNC(retType) extern retType # endif #endif /*------------------------------------------------------------------------ * Plugin setup/cleanup *------------------------------------------------------------------------*/ /* * All plugins are required to implement two functions: * * -- Initialize the plugin. Returns non-zero if successful. * PLUGINFUNC(XpdfBool) xpdfInitPlugin(void); * * -- Free the plugin. * PLUGINFUNC(void) xpdfFreePlugin(void); */ /*------------------------------------------------------------------------ * Types *------------------------------------------------------------------------*/ /* * Standard C boolean -- zero = false, non-zero = true. */ typedef int XpdfBool; #define xpdfTrue 1 #define xpdfFalse 0 /* * PDF document handle. */ typedef struct _XpdfDoc *XpdfDoc; /* * PDF object handle. */ typedef struct _XpdfObject *XpdfObject; /* * Document access permissions. Any of these can be bitwise 'or'ed * together. If xpdfPermissionOpen is not included, the document * cannot be opened at all, and the other bits are ignored. */ typedef unsigned int XpdfPermission; #define xpdfPermissionOpen (1 << 0) #define xpdfPermissionPrint (1 << 2) #define xpdfPermissionChange (1 << 3) #define xpdfPermissionCopy (1 << 4) #define xpdfPermissionNotes (1 << 5) /*------------------------------------------------------------------------ * Security handler *------------------------------------------------------------------------*/ /* * XpdfSecurityHandler - a security handler plugin should create one * of these and pass it to xpdfRegisterSecurityHandler. */ #ifdef __cplusplus struct XpdfSecurityHandler { #else typedef struct { #endif /* * Version of the security handler spec (this document) -- use * xpdfPluginAPIVersion. */ int version; /* * Security handler name. */ char *name; /* * Any global data the security handler needs. XpdfViewer will pass * this pointer to all handler functions as the * argument. */ void *handlerData; /* * Allocate and initialize data for a new document. XpdfViewer will * pass the returned pointer to all other handler functions as the * argument. Returns non-zero if successful. */ XpdfBool (*newDoc)(void *handlerData, XpdfDoc doc, XpdfObject encryptDict, void **docData); /* * Free the data allocated by newDoc. */ void (*freeDoc)(void *handlerData, void *docData); /* * Construct authorization data based on the supplied owner and user * passwords (either or both of which may be NULL). This function * is called in "batch" mode, i.e., if the password was supplied on * the command line or via an Xpdf library API. It should not * generate any user interaction (e.g., a password dialog). It is * not required to support this function: the makeAuthData function * pointer can be set to NULL. Returns non-zero if successful. */ XpdfBool (*makeAuthData)(void *handlerData, void *docData, char *ownerPassword, char *userPassword, void **authData); /* * Request any needed information (e.g., a password) from the user, * and construct an authorization data object. Returns non-zero if * successful. */ XpdfBool (*getAuthData)(void *handlerData, void *docData, void **authData); /* * Free the data allocated by getAuthData. */ void (*freeAuthData)(void *handlerData, void *docData, void *authData); /* * Request permission to access the document. This returns all * permissions granted by authData. */ XpdfPermission (*authorize)(void *handlerData, void *docData, void *authData); /* * Get the decryption key and algorithm version associated with the * document. Returns non-zero if successful. */ XpdfBool (*getKey)(void *handlerData, void *docData, char **key, int *keyLen, int *cryptVersion); /* * Free the data allocated by getKey. */ void (*freeKey)(void *handlerData, void *docData, char *key, int keyLen); #ifdef __cplusplus }; #else } XpdfSecurityHandler; #endif /*------------------------------------------------------------------------*/ typedef struct { int version; /*------------------------------------------------------------------------ * Document access functions *------------------------------------------------------------------------*/ /* * Get a document's info dictionary. (The returned object must be * freed with xpdfFreeObj.) */ XpdfObject (*_xpdfGetInfoDict)(XpdfDoc doc); /* * Get a document's catalog ("root") dictionary. (The returned object * must be freed with xpdfFreeObj.) */ XpdfObject (*_xpdfGetCatalog)(XpdfDoc doc); #ifdef _WIN32 /* * Get the handle for the viewer window associated with the specified * document. [Win32 only] */ HWND (*_xpdfWin32GetWindow)(XpdfDoc doc); #else /* * Get the Motif widget for the viewer window associated with the * specified document. [X only] */ Widget (*_xpdfXGetWindow)(XpdfDoc doc); #endif /*------------------------------------------------------------------------ * Object access functions *------------------------------------------------------------------------*/ /* * Check an object's type. */ XpdfBool (*_xpdfObjIsBool)(XpdfObject obj); XpdfBool (*_xpdfObjIsInt)(XpdfObject obj); XpdfBool (*_xpdfObjIsReal)(XpdfObject obj); XpdfBool (*_xpdfObjIsString)(XpdfObject obj); XpdfBool (*_xpdfObjIsName)(XpdfObject obj); XpdfBool (*_xpdfObjIsNull)(XpdfObject obj); XpdfBool (*_xpdfObjIsArray)(XpdfObject obj); XpdfBool (*_xpdfObjIsDict)(XpdfObject obj); XpdfBool (*_xpdfObjIsStream)(XpdfObject obj); XpdfBool (*_xpdfObjIsRef)(XpdfObject obj); /* * Value access. * (Objects returned by xpdfArrayGet and xpdfDictGet must be freed * with xpdfFreeObj.) */ XpdfBool (*_xpdfBoolValue)(XpdfObject obj); int (*_xpdfIntValue)(XpdfObject obj); double (*_xpdfRealValue)(XpdfObject obj); int (*_xpdfStringLength)(XpdfObject obj); char *(*_xpdfStringValue)(XpdfObject obj); char *(*_xpdfNameValue)(XpdfObject obj); int (*_xpdfArrayLength)(XpdfObject obj); XpdfObject (*_xpdfArrayGet)(XpdfObject obj, int idx); XpdfObject (*_xpdfDictGet)(XpdfObject obj, char *key); /* * Object destruction. NB: *all* objects must be freed after use. */ void (*_xpdfFreeObj)(XpdfObject obj); /*------------------------------------------------------------------------ * Memory allocation functions *------------------------------------------------------------------------*/ void *(*_xpdfMalloc)(int size); void *(*_xpdfRealloc)(void *p, int size); void (*_xpdfFree)(void *p); /*------------------------------------------------------------------------ * Security handler functions *------------------------------------------------------------------------*/ /* * Register a new security handler. */ void (*_xpdfRegisterSecurityHandler)(XpdfSecurityHandler *handler); /*------------------------------------------------------------------------*/ } XpdfPluginVecTable; #ifdef _WIN32 extern __declspec(dllexport) XpdfPluginVecTable xpdfPluginVecTable; #define xpdfPluginSetup \ extern __declspec(dllexport) \ XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion}; #else extern XpdfPluginVecTable xpdfPluginVecTable; #define xpdfPluginSetup \ XpdfPluginVecTable xpdfPluginVecTable = {xpdfPluginAPIVersion}; #endif #define xpdfGetInfoDict (*xpdfPluginVecTable._xpdfGetInfoDict) #define xpdfGetCatalog (*xpdfPluginVecTable._xpdfGetCatalog) #ifdef _WIN32 #define xpdfWin32GetWindow (*xpdfPluginVecTable._xpdfWin32GetWindow) #else #define xpdfXGetWindow (*xpdfPluginVecTable._xpdfXGetWindow) #endif #define xpdfObjIsBool (*xpdfPluginVecTable._xpdfObjIsBool) #define xpdfObjIsInt (*xpdfPluginVecTable._xpdfObjIsInt) #define xpdfObjIsReal (*xpdfPluginVecTable._xpdfObjIsReal) #define xpdfObjIsString (*xpdfPluginVecTable._xpdfObjIsString) #define xpdfObjIsName (*xpdfPluginVecTable._xpdfObjIsName) #define xpdfObjIsNull (*xpdfPluginVecTable._xpdfObjIsNull) #define xpdfObjIsArray (*xpdfPluginVecTable._xpdfObjIsArray) #define xpdfObjIsDict (*xpdfPluginVecTable._xpdfObjIsDict) #define xpdfObjIsStream (*xpdfPluginVecTable._xpdfObjIsStream) #define xpdfObjIsRef (*xpdfPluginVecTable._xpdfObjIsRef) #define xpdfBoolValue (*xpdfPluginVecTable._xpdfBoolValue) #define xpdfIntValue (*xpdfPluginVecTable._xpdfIntValue) #define xpdfRealValue (*xpdfPluginVecTable._xpdfRealValue) #define xpdfStringLength (*xpdfPluginVecTable._xpdfStringLength) #define xpdfStringValue (*xpdfPluginVecTable._xpdfStringValue) #define xpdfNameValue (*xpdfPluginVecTable._xpdfNameValue) #define xpdfArrayLength (*xpdfPluginVecTable._xpdfArrayLength) #define xpdfArrayGet (*xpdfPluginVecTable._xpdfArrayGet) #define xpdfDictGet (*xpdfPluginVecTable._xpdfDictGet) #define xpdfFreeObj (*xpdfPluginVecTable._xpdfFreeObj) #define xpdfMalloc (*xpdfPluginVecTable._xpdfMalloc) #define xpdfRealloc (*xpdfPluginVecTable._xpdfRealloc) #define xpdfFree (*xpdfPluginVecTable._xpdfFree) #define xpdfRegisterSecurityHandler (*xpdfPluginVecTable._xpdfRegisterSecurityHandler) #ifdef __cplusplus } #endif #endif xpdf-3.03/xpdf/TextOutputDev.h0000644000076400007640000005131511622305345015636 0ustar dereknderekn//======================================================================== // // TextOutputDev.h // // Copyright 1997-2003 Glyph & Cog, LLC // //======================================================================== #ifndef TEXTOUTPUTDEV_H #define TEXTOUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "gtypes.h" #include "GfxFont.h" #include "OutputDev.h" class GString; class GList; class GfxFont; class GfxState; class UnicodeMap; class Link; class TextWord; class TextPool; class TextLine; class TextLineFrag; class TextBlock; class TextFlow; class TextWordList; class TextPage; //------------------------------------------------------------------------ typedef void (*TextOutputFunc)(void *stream, const char *text, int len); //------------------------------------------------------------------------ // TextFontInfo //------------------------------------------------------------------------ class TextFontInfo { public: TextFontInfo(GfxState *state); ~TextFontInfo(); GBool matches(GfxState *state); #if TEXTOUT_WORD_LIST // Get the font name (which may be NULL). GString *getFontName() { return fontName; } // Get font descriptor flags. GBool isFixedWidth() { return flags & fontFixedWidth; } GBool isSerif() { return flags & fontSerif; } GBool isSymbolic() { return flags & fontSymbolic; } GBool isItalic() { return flags & fontItalic; } GBool isBold() { return flags & fontBold; } #endif private: GfxFont *gfxFont; #if TEXTOUT_WORD_LIST GString *fontName; int flags; #endif friend class TextWord; friend class TextPage; }; //------------------------------------------------------------------------ // TextWord //------------------------------------------------------------------------ class TextWord { public: // Constructor. TextWord(GfxState *state, int rotA, double x0, double y0, TextFontInfo *fontA, double fontSize); // Destructor. ~TextWord(); // Add a character to the word. void addChar(GfxState *state, double x, double y, double dx, double dy, int charPosA, int charLen, Unicode u); // Merge onto the end of . void merge(TextWord *word); // Compares to , returning -1 (<), 0 (=), or +1 (>), // based on a primary-axis comparison, e.g., x ordering if rot=0. int primaryCmp(TextWord *word); // Return the distance along the primary axis between and // . double primaryDelta(TextWord *word); static int cmpYX(const void *p1, const void *p2); // Get the TextFontInfo object associated with this word. TextFontInfo *getFontInfo() { return font; } // Get the next TextWord on the linked list. TextWord *getNext() { return next; } #if TEXTOUT_WORD_LIST int getLength() { return len; } Unicode getChar(int idx) { return text[idx]; } GString *getText(); GString *getFontName() { return font->fontName; } void getColor(double *r, double *g, double *b) { *r = colorR; *g = colorG; *b = colorB; } void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } void getCharBBox(int charIdx, double *xMinA, double *yMinA, double *xMaxA, double *yMaxA); double getFontSize() { return fontSize; } int getRotation() { return rot; } int getCharPos() { return charPos[0]; } int getCharLen() { return charPos[len] - charPos[0]; } GBool getSpaceAfter() { return spaceAfter; } #endif GBool isUnderlined() { return underlined; } Link *getLink() { return link; } private: int rot; // rotation, multiple of 90 degrees // (0, 1, 2, or 3) double xMin, xMax; // bounding box x coordinates double yMin, yMax; // bounding box y coordinates double base; // baseline x or y coordinate Unicode *text; // the text double *edge; // "near" edge x or y coord of each char // (plus one extra entry for the last char) int *charPos; // character position (within content stream) // of each char (plus one extra entry for // the last char) int len; // length of text/edge/charPos arrays int size; // size of text/edge/charPos arrays TextFontInfo *font; // font information double fontSize; // font size GBool spaceAfter; // set if there is a space between this // word and the next word on the line TextWord *next; // next word in line #if TEXTOUT_WORD_LIST double colorR, // word color colorG, colorB; #endif GBool underlined; Link *link; friend class TextPool; friend class TextLine; friend class TextBlock; friend class TextFlow; friend class TextWordList; friend class TextPage; }; //------------------------------------------------------------------------ // TextPool //------------------------------------------------------------------------ class TextPool { public: TextPool(); ~TextPool(); TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; } void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; } int getBaseIdx(double base); void addWord(TextWord *word); private: int minBaseIdx; // min baseline bucket index int maxBaseIdx; // max baseline bucket index TextWord **pool; // array of linked lists, one for each // baseline value (multiple of 4 pts) TextWord *cursor; // pointer to last-accessed word int cursorBaseIdx; // baseline bucket index of last-accessed word friend class TextBlock; friend class TextPage; }; //------------------------------------------------------------------------ // TextLine //------------------------------------------------------------------------ class TextLine { public: TextLine(TextBlock *blkA, int rotA, double baseA); ~TextLine(); void addWord(TextWord *word); // Return the distance along the primary axis between and // . double primaryDelta(TextLine *line); // Compares to , returning -1 (<), 0 (=), or +1 (>), // based on a primary-axis comparison, e.g., x ordering if rot=0. int primaryCmp(TextLine *line); // Compares to , returning -1 (<), 0 (=), or +1 (>), // based on a secondary-axis comparison of the baselines, e.g., y // ordering if rot=0. int secondaryCmp(TextLine *line); int cmpYX(TextLine *line); static int cmpXY(const void *p1, const void *p2); void coalesce(UnicodeMap *uMap); // Get the head of the linked list of TextWords. TextWord *getWords() { return words; } // Get the next TextLine on the linked list. TextLine *getNext() { return next; } // Returns true if the last char of the line is a hyphen. GBool isHyphenated() { return hyphenated; } private: TextBlock *blk; // parent block int rot; // text rotation double xMin, xMax; // bounding box x coordinates double yMin, yMax; // bounding box y coordinates double base; // baseline x or y coordinate TextWord *words; // words in this line TextWord *lastWord; // last word in this line Unicode *text; // Unicode text of the line, including // spaces between words double *edge; // "near" edge x or y coord of each char // (plus one extra entry for the last char) int *col; // starting column number of each Unicode char int len; // number of Unicode chars int convertedLen; // total number of converted characters GBool hyphenated; // set if last char is a hyphen TextLine *next; // next line in block friend class TextLineFrag; friend class TextBlock; friend class TextFlow; friend class TextWordList; friend class TextPage; }; //------------------------------------------------------------------------ // TextBlock //------------------------------------------------------------------------ class TextBlock { public: TextBlock(TextPage *pageA, int rotA); ~TextBlock(); void addWord(TextWord *word); void coalesce(UnicodeMap *uMap, double fixedPitch); // Update this block's priMin and priMax values, looking at . void updatePriMinMax(TextBlock *blk); static int cmpXYPrimaryRot(const void *p1, const void *p2); static int cmpYXPrimaryRot(const void *p1, const void *p2); int primaryCmp(TextBlock *blk); double secondaryDelta(TextBlock *blk); // Returns true if is below , relative to the page's // primary rotation. GBool isBelow(TextBlock *blk); // Get the head of the linked list of TextLines. TextLine *getLines() { return lines; } // Get the next TextBlock on the linked list. TextBlock *getNext() { return next; } private: TextPage *page; // the parent page int rot; // text rotation double xMin, xMax; // bounding box x coordinates double yMin, yMax; // bounding box y coordinates double priMin, priMax; // whitespace bounding box along primary axis TextPool *pool; // pool of words (used only until lines // are built) TextLine *lines; // linked list of lines TextLine *curLine; // most recently added line int nLines; // number of lines int charCount; // number of characters in the block int col; // starting column int nColumns; // number of columns in the block TextBlock *next; TextBlock *stackNext; friend class TextLine; friend class TextLineFrag; friend class TextFlow; friend class TextWordList; friend class TextPage; }; //------------------------------------------------------------------------ // TextFlow //------------------------------------------------------------------------ class TextFlow { public: TextFlow(TextPage *pageA, TextBlock *blk); ~TextFlow(); // Add a block to the end of this flow. void addBlock(TextBlock *blk); // Returns true if fits below in the flow, i.e., (1) // it uses a font no larger than the last block added to the flow, // and (2) it fits within the flow's [priMin, priMax] along the // primary axis. GBool blockFits(TextBlock *blk, TextBlock *prevBlk); // Get the head of the linked list of TextBlocks. TextBlock *getBlocks() { return blocks; } // Get the next TextFlow on the linked list. TextFlow *getNext() { return next; } private: TextPage *page; // the parent page double xMin, xMax; // bounding box x coordinates double yMin, yMax; // bounding box y coordinates double priMin, priMax; // whitespace bounding box along primary axis TextBlock *blocks; // blocks in flow TextBlock *lastBlk; // last block in this flow TextFlow *next; friend class TextWordList; friend class TextPage; }; #if TEXTOUT_WORD_LIST //------------------------------------------------------------------------ // TextWordList //------------------------------------------------------------------------ class TextWordList { public: // Build a flat word list, in content stream order (if // text->rawOrder is true), physical layout order (if // is true and text->rawOrder is false), or reading order (if both // flags are false). TextWordList(TextPage *text, GBool physLayout); ~TextWordList(); // Return the number of words on the list. int getLength(); // Return the th word from the list. TextWord *get(int idx); private: GList *words; // [TextWord] }; #endif // TEXTOUT_WORD_LIST //------------------------------------------------------------------------ // TextPage //------------------------------------------------------------------------ class TextPage { public: // Constructor. TextPage(GBool rawOrderA); // Destructor. ~TextPage(); // Start a new page. void startPage(GfxState *state); // End the current page. void endPage(); // Update the current font. void updateFont(GfxState *state); // Begin a new word. void beginWord(GfxState *state, double x0, double y0); // Add a character to the current word. void addChar(GfxState *state, double x, double y, double dx, double dy, CharCode c, int nBytes, Unicode *u, int uLen); // Add invisible characters. void incCharCount(int nChars); // Begin/end an "ActualText" span, where the char indexes are // supplied by a marked content operator rather than the text // drawing operators. void beginActualText(GfxState *state, Unicode *u, int uLen); void endActualText(GfxState *state); // End the current word, sorting it into the list of words. void endWord(); // Add a word, sorting it into the list of words. void addWord(TextWord *word); // Add a (potential) underline. void addUnderline(double x0, double y0, double x1, double y1); // Add a hyperlink. void addLink(int xMin, int yMin, int xMax, int yMax, Link *link); // Coalesce strings that look like parts of the same line. void coalesce(GBool physLayout, double fixedPitch, GBool doHTML); // Find a string. If is true, starts looking at the // top of the page; else if is true, starts looking // immediately after the last find result; else starts looking at // ,. If is true, stops looking at the // bottom of the page; else if is true, stops looking // just before the last find result; else stops looking at // ,. GBool findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, GBool caseSensitive, GBool backward, GBool wholeWord, double *xMin, double *yMin, double *xMax, double *yMax); // Get the text which is inside the specified rectangle. GString *getText(double xMin, double yMin, double xMax, double yMax); // Find a string by character position and length. If found, sets // the text bounding rectangle and returns true; otherwise returns // false. GBool findCharRange(int pos, int length, double *xMin, double *yMin, double *xMax, double *yMax); // Dump contents of page to a file. void dump(void *outputStream, TextOutputFunc outputFunc, GBool physLayout); // Get the head of the linked list of TextFlows. TextFlow *getFlows() { return flows; } #if TEXTOUT_WORD_LIST // Build a flat word list, in content stream order (if // this->rawOrder is true), physical layout order (if // is true and this->rawOrder is false), or reading order (if both // flags are false). TextWordList *makeWordList(GBool physLayout); #endif private: void clear(); void assignColumns(TextLineFrag *frags, int nFrags, int rot); int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s); GBool rawOrder; // keep text in content stream order double pageWidth, pageHeight; // width and height of current page TextWord *curWord; // currently active string int charPos; // next character position (within content // stream) TextFontInfo *curFont; // current font double curFontSize; // current font size int nest; // current nesting level (for Type 3 fonts) int nTinyChars; // number of "tiny" chars seen so far GBool lastCharOverlap; // set if the last added char overlapped the // previous char Unicode *actualText; // current "ActualText" span int actualTextLen; double actualTextX0, actualTextY0, actualTextX1, actualTextY1; int actualTextNBytes; TextPool *pools[4]; // a "pool" of TextWords for each rotation TextFlow *flows; // linked list of flows TextBlock **blocks; // array of blocks, in yx order int nBlocks; // number of blocks int primaryRot; // primary rotation GBool primaryLR; // primary direction (true means L-to-R, // false means R-to-L) TextWord *rawWords; // list of words, in raw order (only if // rawOrder is set) TextWord *rawLastWord; // last word on rawWords list GList *fonts; // all font info objects used on this // page [TextFontInfo] double lastFindXMin, // coordinates of the last "find" result lastFindYMin; GBool haveLastFind; GList *underlines; // [TextUnderline] GList *links; // [TextLink] friend class TextLine; friend class TextLineFrag; friend class TextBlock; friend class TextFlow; friend class TextWordList; }; //------------------------------------------------------------------------ // TextOutputDev //------------------------------------------------------------------------ class TextOutputDev: public OutputDev { public: // Open a text output file. If is NULL, no file is // written (this is useful, e.g., for searching text). If // is true, the original physical layout of the text // is maintained. If is true, the text is kept in // content stream order. TextOutputDev(char *fileName, GBool physLayoutA, double fixedPitchA, GBool rawOrderA, GBool append); // Create a TextOutputDev which will write to a generic stream. If // is true, the original physical layout of the text // is maintained. If is true, the text is kept in // content stream order. TextOutputDev(TextOutputFunc func, void *stream, GBool physLayoutA, double fixedPitchA, GBool rawOrderA); // Destructor. virtual ~TextOutputDev(); // Check if file was successfully created. virtual GBool isOk() { return ok; } //---- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gTrue; } // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gFalse; } // Does this device need non-text content? virtual GBool needNonText() { return gFalse; } // Does this device require incCharCount to be called for text on // non-shown layers? virtual GBool needCharCount() { return gTrue; } //----- initialization and control // Start a page. virtual void startPage(int pageNum, GfxState *state); // End a page. virtual void endPage(); //----- save/restore graphics state virtual void restoreState(GfxState *state); //----- update text state virtual void updateFont(GfxState *state); //----- text drawing virtual void beginString(GfxState *state, GString *s); virtual void endString(GfxState *state); virtual void drawChar(GfxState *state, double x, double y, double dx, double dy, double originX, double originY, CharCode c, int nBytes, Unicode *u, int uLen); virtual void incCharCount(int nChars); virtual void beginActualText(GfxState *state, Unicode *u, int uLen); virtual void endActualText(GfxState *state); //----- path painting virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); //----- link borders virtual void processLink(Link *link); //----- special access // Find a string. If is true, starts looking at the // top of the page; else if is true, starts looking // immediately after the last find result; else starts looking at // ,. If is true, stops looking at the // bottom of the page; else if is true, stops looking // just before the last find result; else stops looking at // ,. GBool findText(Unicode *s, int len, GBool startAtTop, GBool stopAtBottom, GBool startAtLast, GBool stopAtLast, GBool caseSensitive, GBool backward, GBool wholeWord, double *xMin, double *yMin, double *xMax, double *yMax); // Get the text which is inside the specified rectangle. GString *getText(double xMin, double yMin, double xMax, double yMax); // Find a string by character position and length. If found, sets // the text bounding rectangle and returns true; otherwise returns // false. GBool findCharRange(int pos, int length, double *xMin, double *yMin, double *xMax, double *yMax); #if TEXTOUT_WORD_LIST // Build a flat word list, in content stream order (if // this->rawOrder is true), physical layout order (if // this->physLayout is true and this->rawOrder is false), or reading // order (if both flags are false). TextWordList *makeWordList(); #endif // Returns the TextPage object for the last rasterized page, // transferring ownership to the caller. TextPage *takeText(); // Turn extra processing for HTML conversion on or off. void enableHTMLExtras(GBool doHTMLA) { doHTML = doHTMLA; } private: TextOutputFunc outputFunc; // output function void *outputStream; // output stream GBool needClose; // need to close the output file? // (only if outputStream is a FILE*) TextPage *text; // text for the current page GBool physLayout; // maintain original physical layout when // dumping text double fixedPitch; // if physLayout is true and this is non-zero, // assume fixed-pitch characters with this // width GBool rawOrder; // keep text in content stream order GBool doHTML; // extra processing for HTML conversion GBool ok; // set up ok? }; #endif xpdf-3.03/xpdf/BuiltinFontTables.h0000644000076400007640000000105411622305345016415 0ustar dereknderekn//======================================================================== // // BuiltinFontTables.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONTTABLES_H #define BUILTINFONTTABLES_H #include "BuiltinFont.h" #define nBuiltinFonts 14 #define nBuiltinFontSubsts 12 extern BuiltinFont builtinFonts[nBuiltinFonts]; extern BuiltinFont *builtinFontSubst[nBuiltinFontSubsts]; extern void initBuiltinFontTables(); extern void freeBuiltinFontTables(); #endif xpdf-3.03/xpdf/Error.h0000644000076400007640000000233011622305345014114 0ustar dereknderekn//======================================================================== // // Error.h // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ERROR_H #define ERROR_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "config.h" enum ErrorCategory { errSyntaxWarning, // PDF syntax error which can be worked around; // output will probably be correct errSyntaxError, // PDF syntax error which can be worked around; // output will probably be incorrect errConfig, // error in Xpdf config info (xpdfrc file, etc.) errCommandLine, // error in user-supplied parameters, action not // allowed, etc. (only used by command-line tools) errIO, // error in file I/O errNotAllowed, // action not allowed by PDF permission bits errUnimplemented, // unimplemented PDF feature - display will be // incorrect errInternal // internal error - malfunction within the Xpdf code }; extern void setErrorCallback(void (*cbk)(void *data, ErrorCategory category, int pos, char *msg), void *data); extern void CDECL error(ErrorCategory category, int pos, const char *msg, ...); #endif xpdf-3.03/xpdf/JBIG2Stream.cc0000644000076400007640000031537011622305345015145 0ustar dereknderekn//======================================================================== // // JBIG2Stream.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "GList.h" #include "Error.h" #include "JArithmeticDecoder.h" #include "JBIG2Stream.h" //~ share these tables #include "Stream-CCITT.h" //------------------------------------------------------------------------ static int contextSize[4] = { 16, 13, 10, 10 }; static int refContextSize[2] = { 13, 10 }; //------------------------------------------------------------------------ // JBIG2HuffmanTable //------------------------------------------------------------------------ #define jbig2HuffmanLOW 0xfffffffd #define jbig2HuffmanOOB 0xfffffffe #define jbig2HuffmanEOT 0xffffffff struct JBIG2HuffmanTable { int val; Guint prefixLen; Guint rangeLen; // can also be LOW, OOB, or EOT Guint prefix; }; JBIG2HuffmanTable huffTableA[] = { { 0, 1, 4, 0x000 }, { 16, 2, 8, 0x002 }, { 272, 3, 16, 0x006 }, { 65808, 3, 32, 0x007 }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableB[] = { { 0, 1, 0, 0x000 }, { 1, 2, 0, 0x002 }, { 2, 3, 0, 0x006 }, { 3, 4, 3, 0x00e }, { 11, 5, 6, 0x01e }, { 75, 6, 32, 0x03e }, { 0, 6, jbig2HuffmanOOB, 0x03f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableC[] = { { 0, 1, 0, 0x000 }, { 1, 2, 0, 0x002 }, { 2, 3, 0, 0x006 }, { 3, 4, 3, 0x00e }, { 11, 5, 6, 0x01e }, { 0, 6, jbig2HuffmanOOB, 0x03e }, { 75, 7, 32, 0x0fe }, { -256, 8, 8, 0x0fe }, { -257, 8, jbig2HuffmanLOW, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableD[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 0, 0x006 }, { 4, 4, 3, 0x00e }, { 12, 5, 6, 0x01e }, { 76, 5, 32, 0x01f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableE[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 0, 0x006 }, { 4, 4, 3, 0x00e }, { 12, 5, 6, 0x01e }, { 76, 6, 32, 0x03e }, { -255, 7, 8, 0x07e }, { -256, 7, jbig2HuffmanLOW, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableF[] = { { 0, 2, 7, 0x000 }, { 128, 3, 7, 0x002 }, { 256, 3, 8, 0x003 }, { -1024, 4, 9, 0x008 }, { -512, 4, 8, 0x009 }, { -256, 4, 7, 0x00a }, { -32, 4, 5, 0x00b }, { 512, 4, 9, 0x00c }, { 1024, 4, 10, 0x00d }, { -2048, 5, 10, 0x01c }, { -128, 5, 6, 0x01d }, { -64, 5, 5, 0x01e }, { -2049, 6, jbig2HuffmanLOW, 0x03e }, { 2048, 6, 32, 0x03f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableG[] = { { -512, 3, 8, 0x000 }, { 256, 3, 8, 0x001 }, { 512, 3, 9, 0x002 }, { 1024, 3, 10, 0x003 }, { -1024, 4, 9, 0x008 }, { -256, 4, 7, 0x009 }, { -32, 4, 5, 0x00a }, { 0, 4, 5, 0x00b }, { 128, 4, 7, 0x00c }, { -128, 5, 6, 0x01a }, { -64, 5, 5, 0x01b }, { 32, 5, 5, 0x01c }, { 64, 5, 6, 0x01d }, { -1025, 5, jbig2HuffmanLOW, 0x01e }, { 2048, 5, 32, 0x01f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableH[] = { { 0, 2, 1, 0x000 }, { 0, 2, jbig2HuffmanOOB, 0x001 }, { 4, 3, 4, 0x004 }, { -1, 4, 0, 0x00a }, { 22, 4, 4, 0x00b }, { 38, 4, 5, 0x00c }, { 2, 5, 0, 0x01a }, { 70, 5, 6, 0x01b }, { 134, 5, 7, 0x01c }, { 3, 6, 0, 0x03a }, { 20, 6, 1, 0x03b }, { 262, 6, 7, 0x03c }, { 646, 6, 10, 0x03d }, { -2, 7, 0, 0x07c }, { 390, 7, 8, 0x07d }, { -15, 8, 3, 0x0fc }, { -5, 8, 1, 0x0fd }, { -7, 9, 1, 0x1fc }, { -3, 9, 0, 0x1fd }, { -16, 9, jbig2HuffmanLOW, 0x1fe }, { 1670, 9, 32, 0x1ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableI[] = { { 0, 2, jbig2HuffmanOOB, 0x000 }, { -1, 3, 1, 0x002 }, { 1, 3, 1, 0x003 }, { 7, 3, 5, 0x004 }, { -3, 4, 1, 0x00a }, { 43, 4, 5, 0x00b }, { 75, 4, 6, 0x00c }, { 3, 5, 1, 0x01a }, { 139, 5, 7, 0x01b }, { 267, 5, 8, 0x01c }, { 5, 6, 1, 0x03a }, { 39, 6, 2, 0x03b }, { 523, 6, 8, 0x03c }, { 1291, 6, 11, 0x03d }, { -5, 7, 1, 0x07c }, { 779, 7, 9, 0x07d }, { -31, 8, 4, 0x0fc }, { -11, 8, 2, 0x0fd }, { -15, 9, 2, 0x1fc }, { -7, 9, 1, 0x1fd }, { -32, 9, jbig2HuffmanLOW, 0x1fe }, { 3339, 9, 32, 0x1ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableJ[] = { { -2, 2, 2, 0x000 }, { 6, 2, 6, 0x001 }, { 0, 2, jbig2HuffmanOOB, 0x002 }, { -3, 5, 0, 0x018 }, { 2, 5, 0, 0x019 }, { 70, 5, 5, 0x01a }, { 3, 6, 0, 0x036 }, { 102, 6, 5, 0x037 }, { 134, 6, 6, 0x038 }, { 198, 6, 7, 0x039 }, { 326, 6, 8, 0x03a }, { 582, 6, 9, 0x03b }, { 1094, 6, 10, 0x03c }, { -21, 7, 4, 0x07a }, { -4, 7, 0, 0x07b }, { 4, 7, 0, 0x07c }, { 2118, 7, 11, 0x07d }, { -5, 8, 0, 0x0fc }, { 5, 8, 0, 0x0fd }, { -22, 8, jbig2HuffmanLOW, 0x0fe }, { 4166, 8, 32, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableK[] = { { 1, 1, 0, 0x000 }, { 2, 2, 1, 0x002 }, { 4, 4, 0, 0x00c }, { 5, 4, 1, 0x00d }, { 7, 5, 1, 0x01c }, { 9, 5, 2, 0x01d }, { 13, 6, 2, 0x03c }, { 17, 7, 2, 0x07a }, { 21, 7, 3, 0x07b }, { 29, 7, 4, 0x07c }, { 45, 7, 5, 0x07d }, { 77, 7, 6, 0x07e }, { 141, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableL[] = { { 1, 1, 0, 0x000 }, { 2, 2, 0, 0x002 }, { 3, 3, 1, 0x006 }, { 5, 5, 0, 0x01c }, { 6, 5, 1, 0x01d }, { 8, 6, 1, 0x03c }, { 10, 7, 0, 0x07a }, { 11, 7, 1, 0x07b }, { 13, 7, 2, 0x07c }, { 17, 7, 3, 0x07d }, { 25, 7, 4, 0x07e }, { 41, 8, 5, 0x0fe }, { 73, 8, 32, 0x0ff }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableM[] = { { 1, 1, 0, 0x000 }, { 2, 3, 0, 0x004 }, { 7, 3, 3, 0x005 }, { 3, 4, 0, 0x00c }, { 5, 4, 1, 0x00d }, { 4, 5, 0, 0x01c }, { 15, 6, 1, 0x03a }, { 17, 6, 2, 0x03b }, { 21, 6, 3, 0x03c }, { 29, 6, 4, 0x03d }, { 45, 6, 5, 0x03e }, { 77, 7, 6, 0x07e }, { 141, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableN[] = { { 0, 1, 0, 0x000 }, { -2, 3, 0, 0x004 }, { -1, 3, 0, 0x005 }, { 1, 3, 0, 0x006 }, { 2, 3, 0, 0x007 }, { 0, 0, jbig2HuffmanEOT, 0 } }; JBIG2HuffmanTable huffTableO[] = { { 0, 1, 0, 0x000 }, { -1, 3, 0, 0x004 }, { 1, 3, 0, 0x005 }, { -2, 4, 0, 0x00c }, { 2, 4, 0, 0x00d }, { -4, 5, 1, 0x01c }, { 3, 5, 1, 0x01d }, { -8, 6, 2, 0x03c }, { 5, 6, 2, 0x03d }, { -24, 7, 4, 0x07c }, { 9, 7, 4, 0x07d }, { -25, 7, jbig2HuffmanLOW, 0x07e }, { 25, 7, 32, 0x07f }, { 0, 0, jbig2HuffmanEOT, 0 } }; //------------------------------------------------------------------------ // JBIG2HuffmanDecoder //------------------------------------------------------------------------ class JBIG2HuffmanDecoder { public: JBIG2HuffmanDecoder(); ~JBIG2HuffmanDecoder(); void setStream(Stream *strA) { str = strA; } void reset(); // Returns false for OOB, otherwise sets * and returns true. GBool decodeInt(int *x, JBIG2HuffmanTable *table); Guint readBits(Guint n); Guint readBit(); // Sort the table by prefix length and assign prefix values. void buildTable(JBIG2HuffmanTable *table, Guint len); void resetByteCounter() { byteCounter = 0; } Guint getByteCounter() { return byteCounter; } private: Stream *str; Guint buf; Guint bufLen; Guint byteCounter; }; JBIG2HuffmanDecoder::JBIG2HuffmanDecoder() { str = NULL; byteCounter = 0; reset(); } JBIG2HuffmanDecoder::~JBIG2HuffmanDecoder() { } void JBIG2HuffmanDecoder::reset() { buf = 0; bufLen = 0; } //~ optimize this GBool JBIG2HuffmanDecoder::decodeInt(int *x, JBIG2HuffmanTable *table) { Guint i, len, prefix; i = 0; len = 0; prefix = 0; while (table[i].rangeLen != jbig2HuffmanEOT) { while (len < table[i].prefixLen) { prefix = (prefix << 1) | readBit(); ++len; } if (prefix == table[i].prefix) { if (table[i].rangeLen == jbig2HuffmanOOB) { return gFalse; } if (table[i].rangeLen == jbig2HuffmanLOW) { *x = table[i].val - readBits(32); } else if (table[i].rangeLen > 0) { *x = table[i].val + readBits(table[i].rangeLen); } else { *x = table[i].val; } return gTrue; } ++i; } return gFalse; } Guint JBIG2HuffmanDecoder::readBits(Guint n) { Guint x, mask, nLeft; mask = (n == 32) ? 0xffffffff : ((1 << n) - 1); if (bufLen >= n) { x = (buf >> (bufLen - n)) & mask; bufLen -= n; } else { x = buf & ((1 << bufLen) - 1); nLeft = n - bufLen; bufLen = 0; while (nLeft >= 8) { x = (x << 8) | (str->getChar() & 0xff); ++byteCounter; nLeft -= 8; } if (nLeft > 0) { buf = str->getChar(); ++byteCounter; bufLen = 8 - nLeft; x = (x << nLeft) | ((buf >> bufLen) & ((1 << nLeft) - 1)); } } return x; } Guint JBIG2HuffmanDecoder::readBit() { if (bufLen == 0) { buf = str->getChar(); ++byteCounter; bufLen = 8; } --bufLen; return (buf >> bufLen) & 1; } void JBIG2HuffmanDecoder::buildTable(JBIG2HuffmanTable *table, Guint len) { Guint i, j, k, prefix; JBIG2HuffmanTable tab; // stable selection sort: // - entries with prefixLen > 0, in ascending prefixLen order // - entry with prefixLen = 0, rangeLen = EOT // - all other entries with prefixLen = 0 // (on entry, table[len] has prefixLen = 0, rangeLen = EOT) for (i = 0; i < len; ++i) { for (j = i; j < len && table[j].prefixLen == 0; ++j) ; if (j == len) { break; } for (k = j + 1; k < len; ++k) { if (table[k].prefixLen > 0 && table[k].prefixLen < table[j].prefixLen) { j = k; } } if (j != i) { tab = table[j]; for (k = j; k > i; --k) { table[k] = table[k - 1]; } table[i] = tab; } } table[i] = table[len]; // assign prefixes if (table[0].rangeLen != jbig2HuffmanEOT) { i = 0; prefix = 0; table[i++].prefix = prefix++; for (; table[i].rangeLen != jbig2HuffmanEOT; ++i) { prefix <<= table[i].prefixLen - table[i-1].prefixLen; table[i].prefix = prefix++; } } } //------------------------------------------------------------------------ // JBIG2MMRDecoder //------------------------------------------------------------------------ class JBIG2MMRDecoder { public: JBIG2MMRDecoder(); ~JBIG2MMRDecoder(); void setStream(Stream *strA) { str = strA; } void reset(); int get2DCode(); int getBlackCode(); int getWhiteCode(); Guint get24Bits(); void resetByteCounter() { byteCounter = 0; } Guint getByteCounter() { return byteCounter; } void skipTo(Guint length); private: Stream *str; Guint buf; Guint bufLen; Guint nBytesRead; Guint byteCounter; }; JBIG2MMRDecoder::JBIG2MMRDecoder() { str = NULL; byteCounter = 0; reset(); } JBIG2MMRDecoder::~JBIG2MMRDecoder() { } void JBIG2MMRDecoder::reset() { buf = 0; bufLen = 0; nBytesRead = 0; } int JBIG2MMRDecoder::get2DCode() { CCITTCode *p; if (bufLen == 0) { buf = str->getChar() & 0xff; bufLen = 8; ++nBytesRead; ++byteCounter; p = &twoDimTab1[(buf >> 1) & 0x7f]; } else if (bufLen == 8) { p = &twoDimTab1[(buf >> 1) & 0x7f]; } else { p = &twoDimTab1[(buf << (7 - bufLen)) & 0x7f]; if (p->bits < 0 || p->bits > (int)bufLen) { buf = (buf << 8) | (str->getChar() & 0xff); bufLen += 8; ++nBytesRead; ++byteCounter; p = &twoDimTab1[(buf >> (bufLen - 7)) & 0x7f]; } } if (p->bits < 0) { error(errSyntaxError, str->getPos(), "Bad two dim code in JBIG2 MMR stream"); return EOF; } bufLen -= p->bits; return p->n; } int JBIG2MMRDecoder::getWhiteCode() { CCITTCode *p; Guint code; if (bufLen == 0) { buf = str->getChar() & 0xff; bufLen = 8; ++nBytesRead; ++byteCounter; } while (1) { if (bufLen >= 11 && ((buf >> (bufLen - 7)) & 0x7f) == 0) { if (bufLen <= 12) { code = buf << (12 - bufLen); } else { code = buf >> (bufLen - 12); } p = &whiteTab1[code & 0x1f]; } else { if (bufLen <= 9) { code = buf << (9 - bufLen); } else { code = buf >> (bufLen - 9); } p = &whiteTab2[code & 0x1ff]; } if (p->bits > 0 && p->bits <= (int)bufLen) { bufLen -= p->bits; return p->n; } if (bufLen >= 12) { break; } buf = (buf << 8) | (str->getChar() & 0xff); bufLen += 8; ++nBytesRead; ++byteCounter; } error(errSyntaxError, str->getPos(), "Bad white code in JBIG2 MMR stream"); // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop --bufLen; return 1; } int JBIG2MMRDecoder::getBlackCode() { CCITTCode *p; Guint code; if (bufLen == 0) { buf = str->getChar() & 0xff; bufLen = 8; ++nBytesRead; ++byteCounter; } while (1) { if (bufLen >= 10 && ((buf >> (bufLen - 6)) & 0x3f) == 0) { if (bufLen <= 13) { code = buf << (13 - bufLen); } else { code = buf >> (bufLen - 13); } p = &blackTab1[code & 0x7f]; } else if (bufLen >= 7 && ((buf >> (bufLen - 4)) & 0x0f) == 0 && ((buf >> (bufLen - 6)) & 0x03) != 0) { if (bufLen <= 12) { code = buf << (12 - bufLen); } else { code = buf >> (bufLen - 12); } p = &blackTab2[(code & 0xff) - 64]; } else { if (bufLen <= 6) { code = buf << (6 - bufLen); } else { code = buf >> (bufLen - 6); } p = &blackTab3[code & 0x3f]; } if (p->bits > 0 && p->bits <= (int)bufLen) { bufLen -= p->bits; return p->n; } if (bufLen >= 13) { break; } buf = (buf << 8) | (str->getChar() & 0xff); bufLen += 8; ++nBytesRead; ++byteCounter; } error(errSyntaxError, str->getPos(), "Bad black code in JBIG2 MMR stream"); // eat a bit and return a positive number so that the caller doesn't // go into an infinite loop --bufLen; return 1; } Guint JBIG2MMRDecoder::get24Bits() { while (bufLen < 24) { buf = (buf << 8) | (str->getChar() & 0xff); bufLen += 8; ++nBytesRead; ++byteCounter; } return (buf >> (bufLen - 24)) & 0xffffff; } void JBIG2MMRDecoder::skipTo(Guint length) { while (nBytesRead < length) { str->getChar(); ++nBytesRead; ++byteCounter; } } //------------------------------------------------------------------------ // JBIG2Segment //------------------------------------------------------------------------ enum JBIG2SegmentType { jbig2SegBitmap, jbig2SegSymbolDict, jbig2SegPatternDict, jbig2SegCodeTable }; class JBIG2Segment { public: JBIG2Segment(Guint segNumA) { segNum = segNumA; } virtual ~JBIG2Segment() {} void setSegNum(Guint segNumA) { segNum = segNumA; } Guint getSegNum() { return segNum; } virtual JBIG2SegmentType getType() = 0; private: Guint segNum; }; //------------------------------------------------------------------------ // JBIG2Bitmap //------------------------------------------------------------------------ struct JBIG2BitmapPtr { Guchar *p; int shift; int x; }; class JBIG2Bitmap: public JBIG2Segment { public: JBIG2Bitmap(Guint segNumA, int wA, int hA); virtual ~JBIG2Bitmap(); virtual JBIG2SegmentType getType() { return jbig2SegBitmap; } JBIG2Bitmap *copy() { return new JBIG2Bitmap(0, this); } JBIG2Bitmap *getSlice(Guint x, Guint y, Guint wA, Guint hA); void expand(int newH, Guint pixel); void clearToZero(); void clearToOne(); int getWidth() { return w; } int getHeight() { return h; } int getLineSize() { return line; } int getPixel(int x, int y) { return (x < 0 || x >= w || y < 0 || y >= h) ? 0 : (data[y * line + (x >> 3)] >> (7 - (x & 7))) & 1; } void setPixel(int x, int y) { data[y * line + (x >> 3)] |= 1 << (7 - (x & 7)); } void clearPixel(int x, int y) { data[y * line + (x >> 3)] &= 0x7f7f >> (x & 7); } void getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr); int nextPixel(JBIG2BitmapPtr *ptr); void duplicateRow(int yDest, int ySrc); void combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp); Guchar *getDataPtr() { return data; } int getDataSize() { return h * line; } private: JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap); int w, h, line; Guchar *data; }; JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, int wA, int hA): JBIG2Segment(segNumA) { w = wA; h = hA; line = (wA + 7) >> 3; if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) { // force a call to gmalloc(-1), which will throw an exception h = -1; line = 2; } // need to allocate one extra guard byte for use in combine() data = (Guchar *)gmalloc(h * line + 1); data[h * line] = 0; } JBIG2Bitmap::JBIG2Bitmap(Guint segNumA, JBIG2Bitmap *bitmap): JBIG2Segment(segNumA) { w = bitmap->w; h = bitmap->h; line = bitmap->line; if (w <= 0 || h <= 0 || line <= 0 || h >= (INT_MAX - 1) / line) { // force a call to gmalloc(-1), which will throw an exception h = -1; line = 2; } // need to allocate one extra guard byte for use in combine() data = (Guchar *)gmalloc(h * line + 1); memcpy(data, bitmap->data, h * line); data[h * line] = 0; } JBIG2Bitmap::~JBIG2Bitmap() { gfree(data); } //~ optimize this JBIG2Bitmap *JBIG2Bitmap::getSlice(Guint x, Guint y, Guint wA, Guint hA) { JBIG2Bitmap *slice; Guint xx, yy; slice = new JBIG2Bitmap(0, wA, hA); slice->clearToZero(); for (yy = 0; yy < hA; ++yy) { for (xx = 0; xx < wA; ++xx) { if (getPixel(x + xx, y + yy)) { slice->setPixel(xx, yy); } } } return slice; } void JBIG2Bitmap::expand(int newH, Guint pixel) { if (newH <= h || line <= 0 || newH >= (INT_MAX - 1) / line) { return; } // need to allocate one extra guard byte for use in combine() data = (Guchar *)grealloc(data, newH * line + 1); if (pixel) { memset(data + h * line, 0xff, (newH - h) * line); } else { memset(data + h * line, 0x00, (newH - h) * line); } h = newH; data[h * line] = 0; } void JBIG2Bitmap::clearToZero() { memset(data, 0, h * line); } void JBIG2Bitmap::clearToOne() { memset(data, 0xff, h * line); } inline void JBIG2Bitmap::getPixelPtr(int x, int y, JBIG2BitmapPtr *ptr) { if (y < 0 || y >= h || x >= w) { ptr->p = NULL; ptr->shift = 0; // make gcc happy ptr->x = 0; // make gcc happy } else if (x < 0) { ptr->p = &data[y * line]; ptr->shift = 7; ptr->x = x; } else { ptr->p = &data[y * line + (x >> 3)]; ptr->shift = 7 - (x & 7); ptr->x = x; } } inline int JBIG2Bitmap::nextPixel(JBIG2BitmapPtr *ptr) { int pix; if (!ptr->p) { pix = 0; } else if (ptr->x < 0) { ++ptr->x; pix = 0; } else { pix = (*ptr->p >> ptr->shift) & 1; if (++ptr->x == w) { ptr->p = NULL; } else if (ptr->shift == 0) { ++ptr->p; ptr->shift = 7; } else { --ptr->shift; } } return pix; } void JBIG2Bitmap::duplicateRow(int yDest, int ySrc) { memcpy(data + yDest * line, data + ySrc * line, line); } void JBIG2Bitmap::combine(JBIG2Bitmap *bitmap, int x, int y, Guint combOp) { int x0, x1, y0, y1, xx, yy; Guchar *srcPtr, *destPtr; Guint src0, src1, src, dest, s1, s2, m1, m2, m3; GBool oneByte; // check for the pathological case where y = -2^31 if (y < -0x7fffffff) { return; } if (y < 0) { y0 = -y; } else { y0 = 0; } if (y + bitmap->h > h) { y1 = h - y; } else { y1 = bitmap->h; } if (y0 >= y1) { return; } if (x >= 0) { x0 = x & ~7; } else { x0 = 0; } x1 = x + bitmap->w; if (x1 > w) { x1 = w; } if (x0 >= x1) { return; } s1 = x & 7; s2 = 8 - s1; m1 = 0xff >> (x1 & 7); m2 = 0xff << (((x1 & 7) == 0) ? 0 : 8 - (x1 & 7)); m3 = (0xff >> s1) & m2; oneByte = x0 == ((x1 - 1) & ~7); for (yy = y0; yy < y1; ++yy) { // one byte per line -- need to mask both left and right side if (oneByte) { if (x >= 0) { destPtr = data + (y + yy) * line + (x >> 3); srcPtr = bitmap->data + yy * bitmap->line; dest = *destPtr; src1 = *srcPtr; switch (combOp) { case 0: // or dest |= (src1 >> s1) & m2; break; case 1: // and dest &= ((0xff00 | src1) >> s1) | m1; break; case 2: // xor dest ^= (src1 >> s1) & m2; break; case 3: // xnor dest ^= ((src1 ^ 0xff) >> s1) & m2; break; case 4: // replace dest = (dest & ~m3) | ((src1 >> s1) & m3); break; } *destPtr = dest; } else { destPtr = data + (y + yy) * line; srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); dest = *destPtr; src1 = *srcPtr; switch (combOp) { case 0: // or dest |= src1 & m2; break; case 1: // and dest &= src1 | m1; break; case 2: // xor dest ^= src1 & m2; break; case 3: // xnor dest ^= (src1 ^ 0xff) & m2; break; case 4: // replace dest = (src1 & m2) | (dest & m1); break; } *destPtr = dest; } // multiple bytes per line -- need to mask left side of left-most // byte and right side of right-most byte } else { // left-most byte if (x >= 0) { destPtr = data + (y + yy) * line + (x >> 3); srcPtr = bitmap->data + yy * bitmap->line; src1 = *srcPtr++; dest = *destPtr; switch (combOp) { case 0: // or dest |= src1 >> s1; break; case 1: // and dest &= (0xff00 | src1) >> s1; break; case 2: // xor dest ^= src1 >> s1; break; case 3: // xnor dest ^= (src1 ^ 0xff) >> s1; break; case 4: // replace dest = (dest & (0xff << s2)) | (src1 >> s1); break; } *destPtr++ = dest; xx = x0 + 8; } else { destPtr = data + (y + yy) * line; srcPtr = bitmap->data + yy * bitmap->line + (-x >> 3); src1 = *srcPtr++; xx = x0; } // middle bytes for (; xx < x1 - 8; xx += 8) { dest = *destPtr; src0 = src1; src1 = *srcPtr++; src = (((src0 << 8) | src1) >> s1) & 0xff; switch (combOp) { case 0: // or dest |= src; break; case 1: // and dest &= src; break; case 2: // xor dest ^= src; break; case 3: // xnor dest ^= src ^ 0xff; break; case 4: // replace dest = src; break; } *destPtr++ = dest; } // right-most byte // note: this last byte (src1) may not actually be used, depending // on the values of s1, m1, and m2 - and in fact, it may be off // the edge of the source bitmap, which means we need to allocate // one extra guard byte at the end of each bitmap dest = *destPtr; src0 = src1; src1 = *srcPtr++; src = (((src0 << 8) | src1) >> s1) & 0xff; switch (combOp) { case 0: // or dest |= src & m2; break; case 1: // and dest &= src | m1; break; case 2: // xor dest ^= src & m2; break; case 3: // xnor dest ^= (src ^ 0xff) & m2; break; case 4: // replace dest = (src & m2) | (dest & m1); break; } *destPtr = dest; } } } //------------------------------------------------------------------------ // JBIG2SymbolDict //------------------------------------------------------------------------ class JBIG2SymbolDict: public JBIG2Segment { public: JBIG2SymbolDict(Guint segNumA, Guint sizeA); virtual ~JBIG2SymbolDict(); virtual JBIG2SegmentType getType() { return jbig2SegSymbolDict; } Guint getSize() { return size; } void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } void setGenericRegionStats(JArithmeticDecoderStats *stats) { genericRegionStats = stats; } void setRefinementRegionStats(JArithmeticDecoderStats *stats) { refinementRegionStats = stats; } JArithmeticDecoderStats *getGenericRegionStats() { return genericRegionStats; } JArithmeticDecoderStats *getRefinementRegionStats() { return refinementRegionStats; } private: Guint size; JBIG2Bitmap **bitmaps; JArithmeticDecoderStats *genericRegionStats; JArithmeticDecoderStats *refinementRegionStats; }; JBIG2SymbolDict::JBIG2SymbolDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { Guint i; size = sizeA; bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); for (i = 0; i < size; ++i) { bitmaps[i] = NULL; } genericRegionStats = NULL; refinementRegionStats = NULL; } JBIG2SymbolDict::~JBIG2SymbolDict() { Guint i; for (i = 0; i < size; ++i) { if (bitmaps[i]) { delete bitmaps[i]; } } gfree(bitmaps); if (genericRegionStats) { delete genericRegionStats; } if (refinementRegionStats) { delete refinementRegionStats; } } //------------------------------------------------------------------------ // JBIG2PatternDict //------------------------------------------------------------------------ class JBIG2PatternDict: public JBIG2Segment { public: JBIG2PatternDict(Guint segNumA, Guint sizeA); virtual ~JBIG2PatternDict(); virtual JBIG2SegmentType getType() { return jbig2SegPatternDict; } Guint getSize() { return size; } void setBitmap(Guint idx, JBIG2Bitmap *bitmap) { bitmaps[idx] = bitmap; } JBIG2Bitmap *getBitmap(Guint idx) { return bitmaps[idx]; } private: Guint size; JBIG2Bitmap **bitmaps; }; JBIG2PatternDict::JBIG2PatternDict(Guint segNumA, Guint sizeA): JBIG2Segment(segNumA) { size = sizeA; bitmaps = (JBIG2Bitmap **)gmallocn(size, sizeof(JBIG2Bitmap *)); } JBIG2PatternDict::~JBIG2PatternDict() { Guint i; for (i = 0; i < size; ++i) { delete bitmaps[i]; } gfree(bitmaps); } //------------------------------------------------------------------------ // JBIG2CodeTable //------------------------------------------------------------------------ class JBIG2CodeTable: public JBIG2Segment { public: JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA); virtual ~JBIG2CodeTable(); virtual JBIG2SegmentType getType() { return jbig2SegCodeTable; } JBIG2HuffmanTable *getHuffTable() { return table; } private: JBIG2HuffmanTable *table; }; JBIG2CodeTable::JBIG2CodeTable(Guint segNumA, JBIG2HuffmanTable *tableA): JBIG2Segment(segNumA) { table = tableA; } JBIG2CodeTable::~JBIG2CodeTable() { gfree(table); } //------------------------------------------------------------------------ // JBIG2Stream //------------------------------------------------------------------------ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA): FilterStream(strA) { pageBitmap = NULL; arithDecoder = new JArithmeticDecoder(); genericRegionStats = new JArithmeticDecoderStats(1 << 1); refinementRegionStats = new JArithmeticDecoderStats(1 << 1); iadhStats = new JArithmeticDecoderStats(1 << 9); iadwStats = new JArithmeticDecoderStats(1 << 9); iaexStats = new JArithmeticDecoderStats(1 << 9); iaaiStats = new JArithmeticDecoderStats(1 << 9); iadtStats = new JArithmeticDecoderStats(1 << 9); iaitStats = new JArithmeticDecoderStats(1 << 9); iafsStats = new JArithmeticDecoderStats(1 << 9); iadsStats = new JArithmeticDecoderStats(1 << 9); iardxStats = new JArithmeticDecoderStats(1 << 9); iardyStats = new JArithmeticDecoderStats(1 << 9); iardwStats = new JArithmeticDecoderStats(1 << 9); iardhStats = new JArithmeticDecoderStats(1 << 9); iariStats = new JArithmeticDecoderStats(1 << 9); iaidStats = new JArithmeticDecoderStats(1 << 1); huffDecoder = new JBIG2HuffmanDecoder(); mmrDecoder = new JBIG2MMRDecoder(); globalsStreamA->copy(&globalsStream); segments = globalSegments = NULL; curStr = NULL; dataPtr = dataEnd = NULL; } JBIG2Stream::~JBIG2Stream() { close(); globalsStream.free(); delete arithDecoder; delete genericRegionStats; delete refinementRegionStats; delete iadhStats; delete iadwStats; delete iaexStats; delete iaaiStats; delete iadtStats; delete iaitStats; delete iafsStats; delete iadsStats; delete iardxStats; delete iardyStats; delete iardwStats; delete iardhStats; delete iariStats; delete iaidStats; delete huffDecoder; delete mmrDecoder; delete str; } void JBIG2Stream::reset() { // read the globals stream globalSegments = new GList(); if (globalsStream.isStream()) { segments = globalSegments; curStr = globalsStream.getStream(); curStr->reset(); arithDecoder->setStream(curStr); huffDecoder->setStream(curStr); mmrDecoder->setStream(curStr); readSegments(); curStr->close(); } // read the main stream segments = new GList(); curStr = str; curStr->reset(); arithDecoder->setStream(curStr); huffDecoder->setStream(curStr); mmrDecoder->setStream(curStr); readSegments(); if (pageBitmap) { dataPtr = pageBitmap->getDataPtr(); dataEnd = dataPtr + pageBitmap->getDataSize(); } else { dataPtr = dataEnd = NULL; } } void JBIG2Stream::close() { if (pageBitmap) { delete pageBitmap; pageBitmap = NULL; } if (segments) { deleteGList(segments, JBIG2Segment); segments = NULL; } if (globalSegments) { deleteGList(globalSegments, JBIG2Segment); globalSegments = NULL; } dataPtr = dataEnd = NULL; FilterStream::close(); } int JBIG2Stream::getChar() { if (dataPtr && dataPtr < dataEnd) { return (*dataPtr++ ^ 0xff) & 0xff; } return EOF; } int JBIG2Stream::lookChar() { if (dataPtr && dataPtr < dataEnd) { return (*dataPtr ^ 0xff) & 0xff; } return EOF; } int JBIG2Stream::getBlock(char *blk, int size) { int n, i; if (size <= 0) { return 0; } if (dataEnd - dataPtr < size) { n = (int)(dataEnd - dataPtr); } else { n = size; } for (i = 0; i < n; ++i) { blk[i] = *dataPtr++ ^ 0xff; } return n; } GString *JBIG2Stream::getPSFilter(int psLevel, const char *indent) { return NULL; } GBool JBIG2Stream::isBinary(GBool last) { return str->isBinary(gTrue); } void JBIG2Stream::readSegments() { Guint segNum, segFlags, segType, page, segLength; Guint refFlags, nRefSegs; Guint *refSegs; int c1, c2, c3; Guint i; while (readULong(&segNum)) { // segment header flags if (!readUByte(&segFlags)) { goto eofError1; } segType = segFlags & 0x3f; // referred-to segment count and retention flags if (!readUByte(&refFlags)) { goto eofError1; } nRefSegs = refFlags >> 5; if (nRefSegs == 7) { if ((c1 = curStr->getChar()) == EOF || (c2 = curStr->getChar()) == EOF || (c3 = curStr->getChar()) == EOF) { goto eofError1; } refFlags = (refFlags << 24) | (c1 << 16) | (c2 << 8) | c3; nRefSegs = refFlags & 0x1fffffff; for (i = 0; i < (nRefSegs + 9) >> 3; ++i) { if ((c1 = curStr->getChar()) == EOF) { goto eofError1; } } } // referred-to segment numbers refSegs = (Guint *)gmallocn(nRefSegs, sizeof(Guint)); if (segNum <= 256) { for (i = 0; i < nRefSegs; ++i) { if (!readUByte(&refSegs[i])) { goto eofError2; } } } else if (segNum <= 65536) { for (i = 0; i < nRefSegs; ++i) { if (!readUWord(&refSegs[i])) { goto eofError2; } } } else { for (i = 0; i < nRefSegs; ++i) { if (!readULong(&refSegs[i])) { goto eofError2; } } } // segment page association if (segFlags & 0x40) { if (!readULong(&page)) { goto eofError2; } } else { if (!readUByte(&page)) { goto eofError2; } } // segment data length if (!readULong(&segLength)) { goto eofError2; } // check for missing page information segment if (!pageBitmap && ((segType >= 4 && segType <= 7) || (segType >= 20 && segType <= 43))) { error(errSyntaxError, getPos(), "First JBIG2 segment associated with a page must be a page information segment"); goto syntaxError; } // read the segment data arithDecoder->resetByteCounter(); huffDecoder->resetByteCounter(); mmrDecoder->resetByteCounter(); byteCounter = 0; switch (segType) { case 0: if (!readSymbolDictSeg(segNum, segLength, refSegs, nRefSegs)) { goto syntaxError; } break; case 4: readTextRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); break; case 6: readTextRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); break; case 7: readTextRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); break; case 16: readPatternDictSeg(segNum, segLength); break; case 20: readHalftoneRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); break; case 22: readHalftoneRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); break; case 23: readHalftoneRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); break; case 36: readGenericRegionSeg(segNum, gFalse, gFalse, segLength); break; case 38: readGenericRegionSeg(segNum, gTrue, gFalse, segLength); break; case 39: readGenericRegionSeg(segNum, gTrue, gTrue, segLength); break; case 40: readGenericRefinementRegionSeg(segNum, gFalse, gFalse, segLength, refSegs, nRefSegs); break; case 42: readGenericRefinementRegionSeg(segNum, gTrue, gFalse, segLength, refSegs, nRefSegs); break; case 43: readGenericRefinementRegionSeg(segNum, gTrue, gTrue, segLength, refSegs, nRefSegs); break; case 48: readPageInfoSeg(segLength); break; case 50: readEndOfStripeSeg(segLength); break; case 52: readProfilesSeg(segLength); break; case 53: readCodeTableSeg(segNum, segLength); break; case 62: readExtensionSeg(segLength); break; default: error(errSyntaxError, getPos(), "Unknown segment type in JBIG2 stream"); for (i = 0; i < segLength; ++i) { if ((c1 = curStr->getChar()) == EOF) { goto eofError2; } } break; } // skip any unused data at the end of the segment // (except for immediate generic region segments which have // 0xffffffff = unspecified length) if (!(segType == 38 && segLength == 0xffffffff)) { byteCounter += arithDecoder->getByteCounter(); byteCounter += huffDecoder->getByteCounter(); byteCounter += mmrDecoder->getByteCounter(); // do a sanity check on byteCounter vs segLength -- if there is // a problem, abort the decode if (byteCounter > segLength || segLength - byteCounter > 65536) { error(errSyntaxError, getPos(), "Invalid segment length in JBIG2 stream"); gfree(refSegs); break; } while (byteCounter < segLength) { if (curStr->getChar() == EOF) { break; } ++byteCounter; } } gfree(refSegs); } return; syntaxError: gfree(refSegs); return; eofError2: gfree(refSegs); eofError1: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } GBool JBIG2Stream::readSymbolDictSeg(Guint segNum, Guint length, Guint *refSegs, Guint nRefSegs) { JBIG2SymbolDict *symbolDict; JBIG2HuffmanTable *huffDHTable, *huffDWTable; JBIG2HuffmanTable *huffBMSizeTable, *huffAggInstTable; JBIG2Segment *seg; GList *codeTables; JBIG2SymbolDict *inputSymbolDict; Guint flags, sdTemplate, sdrTemplate, huff, refAgg; Guint huffDH, huffDW, huffBMSize, huffAggInst; Guint contextUsed, contextRetained; int sdATX[4], sdATY[4], sdrATX[2], sdrATY[2]; Guint numExSyms, numNewSyms, numInputSyms, symCodeLen; JBIG2Bitmap **bitmaps; JBIG2Bitmap *collBitmap, *refBitmap; Guint *symWidths; Guint symHeight, symWidth, totalWidth, x, symID; int dh, dw, refAggNum, refDX, refDY, bmSize; GBool ex; int run, cnt, c; Guint i, j, k; Guchar *p; symWidths = NULL; // symbol dictionary flags if (!readUWord(&flags)) { goto eofError; } sdTemplate = (flags >> 10) & 3; sdrTemplate = (flags >> 12) & 1; huff = flags & 1; refAgg = (flags >> 1) & 1; huffDH = (flags >> 2) & 3; huffDW = (flags >> 4) & 3; huffBMSize = (flags >> 6) & 1; huffAggInst = (flags >> 7) & 1; contextUsed = (flags >> 8) & 1; contextRetained = (flags >> 9) & 1; // symbol dictionary AT flags if (!huff) { if (sdTemplate == 0) { if (!readByte(&sdATX[0]) || !readByte(&sdATY[0]) || !readByte(&sdATX[1]) || !readByte(&sdATY[1]) || !readByte(&sdATX[2]) || !readByte(&sdATY[2]) || !readByte(&sdATX[3]) || !readByte(&sdATY[3])) { goto eofError; } } else { if (!readByte(&sdATX[0]) || !readByte(&sdATY[0])) { goto eofError; } } } // symbol dictionary refinement AT flags if (refAgg && !sdrTemplate) { if (!readByte(&sdrATX[0]) || !readByte(&sdrATY[0]) || !readByte(&sdrATX[1]) || !readByte(&sdrATY[1])) { goto eofError; } } // SDNUMEXSYMS and SDNUMNEWSYMS if (!readULong(&numExSyms) || !readULong(&numNewSyms)) { goto eofError; } // get referenced segments: input symbol dictionaries and code tables codeTables = new GList(); numInputSyms = 0; for (i = 0; i < nRefSegs; ++i) { if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { j = ((JBIG2SymbolDict *)seg)->getSize(); if (numInputSyms > UINT_MAX - j) { error(errSyntaxError, getPos(), "Too many input symbols in JBIG2 symbol dictionary"); delete codeTables; goto eofError; } numInputSyms += j; } else if (seg->getType() == jbig2SegCodeTable) { codeTables->append(seg); } } } if (numInputSyms > UINT_MAX - numNewSyms) { error(errSyntaxError, getPos(), "Too many input symbols in JBIG2 symbol dictionary"); delete codeTables; goto eofError; } // compute symbol code length i = numInputSyms + numNewSyms; if (i <= 1) { symCodeLen = huff ? 1 : 0; } else { --i; symCodeLen = 0; // i = floor((numSyms-1) / 2^symCodeLen) while (i > 0) { ++symCodeLen; i >>= 1; } } // get the input symbol bitmaps bitmaps = (JBIG2Bitmap **)gmallocn(numInputSyms + numNewSyms, sizeof(JBIG2Bitmap *)); for (i = 0; i < numInputSyms + numNewSyms; ++i) { bitmaps[i] = NULL; } k = 0; inputSymbolDict = NULL; for (i = 0; i < nRefSegs; ++i) { if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { inputSymbolDict = (JBIG2SymbolDict *)seg; for (j = 0; j < inputSymbolDict->getSize(); ++j) { bitmaps[k++] = inputSymbolDict->getBitmap(j); } } } } // get the Huffman tables huffDHTable = huffDWTable = NULL; // make gcc happy huffBMSizeTable = huffAggInstTable = NULL; // make gcc happy i = 0; if (huff) { if (huffDH == 0) { huffDHTable = huffTableD; } else if (huffDH == 1) { huffDHTable = huffTableE; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffDW == 0) { huffDWTable = huffTableB; } else if (huffDW == 1) { huffDWTable = huffTableC; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffBMSize == 0) { huffBMSizeTable = huffTableA; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffBMSizeTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffAggInst == 0) { huffAggInstTable = huffTableA; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffAggInstTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } } delete codeTables; // set up the Huffman decoder if (huff) { huffDecoder->reset(); // set up the arithmetic decoder } else { if (contextUsed && inputSymbolDict) { resetGenericStats(sdTemplate, inputSymbolDict->getGenericRegionStats()); } else { resetGenericStats(sdTemplate, NULL); } resetIntStats(symCodeLen); arithDecoder->start(); } // set up the arithmetic decoder for refinement/aggregation if (refAgg) { if (contextUsed && inputSymbolDict) { resetRefinementStats(sdrTemplate, inputSymbolDict->getRefinementRegionStats()); } else { resetRefinementStats(sdrTemplate, NULL); } } // allocate symbol widths storage if (huff && !refAgg) { symWidths = (Guint *)gmallocn(numNewSyms, sizeof(Guint)); } symHeight = 0; i = 0; while (i < numNewSyms) { // read the height class delta height if (huff) { huffDecoder->decodeInt(&dh, huffDHTable); } else { arithDecoder->decodeInt(&dh, iadhStats); } if (dh < 0 && (Guint)-dh >= symHeight) { error(errSyntaxError, getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); goto syntaxError; } symHeight += dh; symWidth = 0; totalWidth = 0; j = i; // read the symbols in this height class while (1) { // read the delta width if (huff) { if (!huffDecoder->decodeInt(&dw, huffDWTable)) { break; } } else { if (!arithDecoder->decodeInt(&dw, iadwStats)) { break; } } if (dw < 0 && (Guint)-dw >= symWidth) { error(errSyntaxError, getPos(), "Bad delta-height value in JBIG2 symbol dictionary"); goto syntaxError; } symWidth += dw; if (i >= numNewSyms) { error(errSyntaxError, getPos(), "Too many symbols in JBIG2 symbol dictionary"); goto syntaxError; } // using a collective bitmap, so don't read a bitmap here if (huff && !refAgg) { symWidths[i] = symWidth; totalWidth += symWidth; // refinement/aggregate coding } else if (refAgg) { if (huff) { if (!huffDecoder->decodeInt(&refAggNum, huffAggInstTable)) { break; } } else { if (!arithDecoder->decodeInt(&refAggNum, iaaiStats)) { break; } } #if 0 //~ This special case was added about a year before the final draft //~ of the JBIG2 spec was released. I have encountered some old //~ JBIG2 images that predate it. if (0) { #else if (refAggNum == 1) { #endif if (huff) { symID = huffDecoder->readBits(symCodeLen); huffDecoder->decodeInt(&refDX, huffTableO); huffDecoder->decodeInt(&refDY, huffTableO); huffDecoder->decodeInt(&bmSize, huffTableA); huffDecoder->reset(); arithDecoder->start(); } else { symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); arithDecoder->decodeInt(&refDX, iardxStats); arithDecoder->decodeInt(&refDY, iardyStats); } if (symID >= numInputSyms + i) { error(errSyntaxError, getPos(), "Invalid symbol ID in JBIG2 symbol dictionary"); goto syntaxError; } refBitmap = bitmaps[symID]; bitmaps[numInputSyms + i] = readGenericRefinementRegion(symWidth, symHeight, sdrTemplate, gFalse, refBitmap, refDX, refDY, sdrATX, sdrATY); //~ do we need to use the bmSize value here (in Huffman mode)? } else { bitmaps[numInputSyms + i] = readTextRegion(huff, gTrue, symWidth, symHeight, refAggNum, 0, numInputSyms + i, NULL, symCodeLen, bitmaps, 0, 0, 0, 1, 0, huffTableF, huffTableH, huffTableK, huffTableO, huffTableO, huffTableO, huffTableO, huffTableA, sdrTemplate, sdrATX, sdrATY); } // non-ref/agg coding } else { bitmaps[numInputSyms + i] = readGenericBitmap(gFalse, symWidth, symHeight, sdTemplate, gFalse, gFalse, NULL, sdATX, sdATY, 0); } ++i; } // read the collective bitmap if (huff && !refAgg) { huffDecoder->decodeInt(&bmSize, huffBMSizeTable); huffDecoder->reset(); if (bmSize == 0) { collBitmap = new JBIG2Bitmap(0, totalWidth, symHeight); bmSize = symHeight * ((totalWidth + 7) >> 3); p = collBitmap->getDataPtr(); for (k = 0; k < (Guint)bmSize; ++k) { if ((c = curStr->getChar()) == EOF) { break; } *p++ = (Guchar)c; ++byteCounter; } } else { collBitmap = readGenericBitmap(gTrue, totalWidth, symHeight, 0, gFalse, gFalse, NULL, NULL, NULL, bmSize); } x = 0; for (; j < i; ++j) { bitmaps[numInputSyms + j] = collBitmap->getSlice(x, 0, symWidths[j], symHeight); x += symWidths[j]; } delete collBitmap; } } // create the symbol dict object symbolDict = new JBIG2SymbolDict(segNum, numExSyms); // exported symbol list i = j = 0; ex = gFalse; while (i < numInputSyms + numNewSyms) { if (huff) { huffDecoder->decodeInt(&run, huffTableA); } else { arithDecoder->decodeInt(&run, iaexStats); } if (i + run > numInputSyms + numNewSyms || (ex && j + run > numExSyms)) { error(errSyntaxError, getPos(), "Too many exported symbols in JBIG2 symbol dictionary"); delete symbolDict; goto syntaxError; } if (ex) { for (cnt = 0; cnt < run; ++cnt) { symbolDict->setBitmap(j++, bitmaps[i++]->copy()); } } else { i += run; } ex = !ex; } if (j != numExSyms) { error(errSyntaxError, getPos(), "Too few symbols in JBIG2 symbol dictionary"); delete symbolDict; goto syntaxError; } for (i = 0; i < numNewSyms; ++i) { delete bitmaps[numInputSyms + i]; } gfree(bitmaps); if (symWidths) { gfree(symWidths); } // save the arithmetic decoder stats if (!huff && contextRetained) { symbolDict->setGenericRegionStats(genericRegionStats->copy()); if (refAgg) { symbolDict->setRefinementRegionStats(refinementRegionStats->copy()); } } // store the new symbol dict segments->append(symbolDict); return gTrue; codeTableError: error(errSyntaxError, getPos(), "Missing code table in JBIG2 symbol dictionary"); delete codeTables; syntaxError: for (i = 0; i < numNewSyms; ++i) { if (bitmaps[numInputSyms + i]) { delete bitmaps[numInputSyms + i]; } } gfree(bitmaps); if (symWidths) { gfree(symWidths); } return gFalse; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); return gFalse; } void JBIG2Stream::readTextRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs) { JBIG2Bitmap *bitmap; JBIG2HuffmanTable runLengthTab[36]; JBIG2HuffmanTable *symCodeTab; JBIG2HuffmanTable *huffFSTable, *huffDSTable, *huffDTTable; JBIG2HuffmanTable *huffRDWTable, *huffRDHTable; JBIG2HuffmanTable *huffRDXTable, *huffRDYTable, *huffRSizeTable; JBIG2Segment *seg; GList *codeTables; JBIG2SymbolDict *symbolDict; JBIG2Bitmap **syms; Guint w, h, x, y, segInfoFlags, extCombOp; Guint flags, huff, refine, logStrips, refCorner, transposed; Guint combOp, defPixel, templ; int sOffset; Guint huffFlags, huffFS, huffDS, huffDT; Guint huffRDW, huffRDH, huffRDX, huffRDY, huffRSize; Guint numInstances, numSyms, symCodeLen; int atx[2], aty[2]; Guint i, k, kk; int j; // region segment info field if (!readULong(&w) || !readULong(&h) || !readULong(&x) || !readULong(&y) || !readUByte(&segInfoFlags)) { goto eofError; } extCombOp = segInfoFlags & 7; // rest of the text region header if (!readUWord(&flags)) { goto eofError; } huff = flags & 1; refine = (flags >> 1) & 1; logStrips = (flags >> 2) & 3; refCorner = (flags >> 4) & 3; transposed = (flags >> 6) & 1; combOp = (flags >> 7) & 3; defPixel = (flags >> 9) & 1; sOffset = (flags >> 10) & 0x1f; if (sOffset & 0x10) { sOffset |= -1 - 0x0f; } templ = (flags >> 15) & 1; huffFS = huffDS = huffDT = 0; // make gcc happy huffRDW = huffRDH = huffRDX = huffRDY = huffRSize = 0; // make gcc happy if (huff) { if (!readUWord(&huffFlags)) { goto eofError; } huffFS = huffFlags & 3; huffDS = (huffFlags >> 2) & 3; huffDT = (huffFlags >> 4) & 3; huffRDW = (huffFlags >> 6) & 3; huffRDH = (huffFlags >> 8) & 3; huffRDX = (huffFlags >> 10) & 3; huffRDY = (huffFlags >> 12) & 3; huffRSize = (huffFlags >> 14) & 1; } if (refine && templ == 0) { if (!readByte(&atx[0]) || !readByte(&aty[0]) || !readByte(&atx[1]) || !readByte(&aty[1])) { goto eofError; } } if (!readULong(&numInstances)) { goto eofError; } // get symbol dictionaries and tables codeTables = new GList(); numSyms = 0; for (i = 0; i < nRefSegs; ++i) { if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { numSyms += ((JBIG2SymbolDict *)seg)->getSize(); } else if (seg->getType() == jbig2SegCodeTable) { codeTables->append(seg); } } else { error(errSyntaxError, getPos(), "Invalid segment reference in JBIG2 text region"); delete codeTables; return; } } i = numSyms; if (i <= 1) { symCodeLen = huff ? 1 : 0; } else { --i; symCodeLen = 0; // i = floor((numSyms-1) / 2^symCodeLen) while (i > 0) { ++symCodeLen; i >>= 1; } } // get the symbol bitmaps syms = (JBIG2Bitmap **)gmallocn(numSyms, sizeof(JBIG2Bitmap *)); kk = 0; for (i = 0; i < nRefSegs; ++i) { if ((seg = findSegment(refSegs[i]))) { if (seg->getType() == jbig2SegSymbolDict) { symbolDict = (JBIG2SymbolDict *)seg; for (k = 0; k < symbolDict->getSize(); ++k) { syms[kk++] = symbolDict->getBitmap(k); } } } } // get the Huffman tables huffFSTable = huffDSTable = huffDTTable = NULL; // make gcc happy huffRDWTable = huffRDHTable = NULL; // make gcc happy huffRDXTable = huffRDYTable = huffRSizeTable = NULL; // make gcc happy i = 0; if (huff) { if (huffFS == 0) { huffFSTable = huffTableF; } else if (huffFS == 1) { huffFSTable = huffTableG; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffFSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffDS == 0) { huffDSTable = huffTableH; } else if (huffDS == 1) { huffDSTable = huffTableI; } else if (huffDS == 2) { huffDSTable = huffTableJ; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffDSTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffDT == 0) { huffDTTable = huffTableK; } else if (huffDT == 1) { huffDTTable = huffTableL; } else if (huffDT == 2) { huffDTTable = huffTableM; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffDTTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffRDW == 0) { huffRDWTable = huffTableN; } else if (huffRDW == 1) { huffRDWTable = huffTableO; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffRDWTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffRDH == 0) { huffRDHTable = huffTableN; } else if (huffRDH == 1) { huffRDHTable = huffTableO; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffRDHTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffRDX == 0) { huffRDXTable = huffTableN; } else if (huffRDX == 1) { huffRDXTable = huffTableO; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffRDXTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffRDY == 0) { huffRDYTable = huffTableN; } else if (huffRDY == 1) { huffRDYTable = huffTableO; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffRDYTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } if (huffRSize == 0) { huffRSizeTable = huffTableA; } else { if (i >= (Guint)codeTables->getLength()) { goto codeTableError; } huffRSizeTable = ((JBIG2CodeTable *)codeTables->get(i++))->getHuffTable(); } } delete codeTables; // symbol ID Huffman decoding table if (huff) { huffDecoder->reset(); for (i = 0; i < 32; ++i) { runLengthTab[i].val = i; runLengthTab[i].prefixLen = huffDecoder->readBits(4); runLengthTab[i].rangeLen = 0; } runLengthTab[32].val = 0x103; runLengthTab[32].prefixLen = huffDecoder->readBits(4); runLengthTab[32].rangeLen = 2; runLengthTab[33].val = 0x203; runLengthTab[33].prefixLen = huffDecoder->readBits(4); runLengthTab[33].rangeLen = 3; runLengthTab[34].val = 0x20b; runLengthTab[34].prefixLen = huffDecoder->readBits(4); runLengthTab[34].rangeLen = 7; runLengthTab[35].prefixLen = 0; runLengthTab[35].rangeLen = jbig2HuffmanEOT; huffDecoder->buildTable(runLengthTab, 35); symCodeTab = (JBIG2HuffmanTable *)gmallocn(numSyms + 1, sizeof(JBIG2HuffmanTable)); for (i = 0; i < numSyms; ++i) { symCodeTab[i].val = i; symCodeTab[i].rangeLen = 0; } i = 0; while (i < numSyms) { huffDecoder->decodeInt(&j, runLengthTab); if (j > 0x200) { for (j -= 0x200; j && i < numSyms; --j) { symCodeTab[i++].prefixLen = 0; } } else if (j > 0x100) { for (j -= 0x100; j && i < numSyms; --j) { symCodeTab[i].prefixLen = symCodeTab[i-1].prefixLen; ++i; } } else { symCodeTab[i++].prefixLen = j; } } symCodeTab[numSyms].prefixLen = 0; symCodeTab[numSyms].rangeLen = jbig2HuffmanEOT; huffDecoder->buildTable(symCodeTab, numSyms); huffDecoder->reset(); // set up the arithmetic decoder } else { symCodeTab = NULL; resetIntStats(symCodeLen); arithDecoder->start(); } if (refine) { resetRefinementStats(templ, NULL); } bitmap = readTextRegion(huff, refine, w, h, numInstances, logStrips, numSyms, symCodeTab, symCodeLen, syms, defPixel, combOp, transposed, refCorner, sOffset, huffFSTable, huffDSTable, huffDTTable, huffRDWTable, huffRDHTable, huffRDXTable, huffRDYTable, huffRSizeTable, templ, atx, aty); gfree(syms); // combine the region bitmap into the page bitmap if (imm) { if (pageH == 0xffffffff && y + h > curPageH) { pageBitmap->expand(y + h, pageDefPixel); } pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; // store the region bitmap } else { bitmap->setSegNum(segNum); segments->append(bitmap); } // clean up the Huffman decoder if (huff) { gfree(symCodeTab); } return; codeTableError: error(errSyntaxError, getPos(), "Missing code table in JBIG2 text region"); gfree(codeTables); delete syms; return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); return; } JBIG2Bitmap *JBIG2Stream::readTextRegion(GBool huff, GBool refine, int w, int h, Guint numInstances, Guint logStrips, int numSyms, JBIG2HuffmanTable *symCodeTab, Guint symCodeLen, JBIG2Bitmap **syms, Guint defPixel, Guint combOp, Guint transposed, Guint refCorner, int sOffset, JBIG2HuffmanTable *huffFSTable, JBIG2HuffmanTable *huffDSTable, JBIG2HuffmanTable *huffDTTable, JBIG2HuffmanTable *huffRDWTable, JBIG2HuffmanTable *huffRDHTable, JBIG2HuffmanTable *huffRDXTable, JBIG2HuffmanTable *huffRDYTable, JBIG2HuffmanTable *huffRSizeTable, Guint templ, int *atx, int *aty) { JBIG2Bitmap *bitmap; JBIG2Bitmap *symbolBitmap; Guint strips; int t, dt, tt, s, ds, sFirst, j; int rdw, rdh, rdx, rdy, ri, refDX, refDY, bmSize; Guint symID, inst, bw, bh; strips = 1 << logStrips; // allocate the bitmap bitmap = new JBIG2Bitmap(0, w, h); if (defPixel) { bitmap->clearToOne(); } else { bitmap->clearToZero(); } // decode initial T value if (huff) { huffDecoder->decodeInt(&t, huffDTTable); } else { arithDecoder->decodeInt(&t, iadtStats); } t *= -(int)strips; inst = 0; sFirst = 0; while (inst < numInstances) { // decode delta-T if (huff) { huffDecoder->decodeInt(&dt, huffDTTable); } else { arithDecoder->decodeInt(&dt, iadtStats); } t += dt * strips; // first S value if (huff) { huffDecoder->decodeInt(&ds, huffFSTable); } else { arithDecoder->decodeInt(&ds, iafsStats); } sFirst += ds; s = sFirst; // read the instances // (this loop test is here to avoid an infinite loop with damaged // JBIG2 streams where the normal loop exit doesn't get triggered) while (inst < numInstances) { // T value if (strips == 1) { dt = 0; } else if (huff) { dt = huffDecoder->readBits(logStrips); } else { arithDecoder->decodeInt(&dt, iaitStats); } tt = t + dt; // symbol ID if (huff) { if (symCodeTab) { huffDecoder->decodeInt(&j, symCodeTab); symID = (Guint)j; } else { symID = huffDecoder->readBits(symCodeLen); } } else { symID = arithDecoder->decodeIAID(symCodeLen, iaidStats); } if (symID >= (Guint)numSyms) { error(errSyntaxError, getPos(), "Invalid symbol number in JBIG2 text region"); } else { // get the symbol bitmap symbolBitmap = NULL; if (refine) { if (huff) { ri = (int)huffDecoder->readBit(); } else { arithDecoder->decodeInt(&ri, iariStats); } } else { ri = 0; } if (ri) { if (huff) { huffDecoder->decodeInt(&rdw, huffRDWTable); huffDecoder->decodeInt(&rdh, huffRDHTable); huffDecoder->decodeInt(&rdx, huffRDXTable); huffDecoder->decodeInt(&rdy, huffRDYTable); huffDecoder->decodeInt(&bmSize, huffRSizeTable); huffDecoder->reset(); arithDecoder->start(); } else { arithDecoder->decodeInt(&rdw, iardwStats); arithDecoder->decodeInt(&rdh, iardhStats); arithDecoder->decodeInt(&rdx, iardxStats); arithDecoder->decodeInt(&rdy, iardyStats); } refDX = ((rdw >= 0) ? rdw : rdw - 1) / 2 + rdx; refDY = ((rdh >= 0) ? rdh : rdh - 1) / 2 + rdy; symbolBitmap = readGenericRefinementRegion(rdw + syms[symID]->getWidth(), rdh + syms[symID]->getHeight(), templ, gFalse, syms[symID], refDX, refDY, atx, aty); //~ do we need to use the bmSize value here (in Huffman mode)? } else { symbolBitmap = syms[symID]; } // combine the symbol bitmap into the region bitmap //~ something is wrong here - refCorner shouldn't degenerate into //~ two cases bw = symbolBitmap->getWidth() - 1; bh = symbolBitmap->getHeight() - 1; if (transposed) { switch (refCorner) { case 0: // bottom left bitmap->combine(symbolBitmap, tt, s, combOp); break; case 1: // top left bitmap->combine(symbolBitmap, tt, s, combOp); break; case 2: // bottom right bitmap->combine(symbolBitmap, tt - bw, s, combOp); break; case 3: // top right bitmap->combine(symbolBitmap, tt - bw, s, combOp); break; } s += bh; } else { switch (refCorner) { case 0: // bottom left bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 1: // top left bitmap->combine(symbolBitmap, s, tt, combOp); break; case 2: // bottom right bitmap->combine(symbolBitmap, s, tt - bh, combOp); break; case 3: // top right bitmap->combine(symbolBitmap, s, tt, combOp); break; } s += bw; } if (ri) { delete symbolBitmap; } } // next instance ++inst; // next S value if (huff) { if (!huffDecoder->decodeInt(&ds, huffDSTable)) { break; } } else { if (!arithDecoder->decodeInt(&ds, iadsStats)) { break; } } s += sOffset + ds; } } return bitmap; } void JBIG2Stream::readPatternDictSeg(Guint segNum, Guint length) { JBIG2PatternDict *patternDict; JBIG2Bitmap *bitmap; Guint flags, patternW, patternH, grayMax, templ, mmr; int atx[4], aty[4]; Guint i, x; // halftone dictionary flags, pattern width and height, max gray value if (!readUByte(&flags) || !readUByte(&patternW) || !readUByte(&patternH) || !readULong(&grayMax)) { goto eofError; } templ = (flags >> 1) & 3; mmr = flags & 1; // set up the arithmetic decoder if (!mmr) { resetGenericStats(templ, NULL); arithDecoder->start(); } // read the bitmap atx[0] = -(int)patternW; aty[0] = 0; atx[1] = -3; aty[1] = -1; atx[2] = 2; aty[2] = -2; atx[3] = -2; aty[3] = -2; bitmap = readGenericBitmap(mmr, (grayMax + 1) * patternW, patternH, templ, gFalse, gFalse, NULL, atx, aty, length - 7); // create the pattern dict object patternDict = new JBIG2PatternDict(segNum, grayMax + 1); // split up the bitmap x = 0; for (i = 0; i <= grayMax; ++i) { patternDict->setBitmap(i, bitmap->getSlice(x, 0, patternW, patternH)); x += patternW; } // free memory delete bitmap; // store the new pattern dict segments->append(patternDict); return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs) { JBIG2Bitmap *bitmap; JBIG2Segment *seg; JBIG2PatternDict *patternDict; JBIG2Bitmap *skipBitmap; Guint *grayImg; JBIG2Bitmap *grayBitmap; JBIG2Bitmap *patternBitmap; Guint w, h, x, y, segInfoFlags, extCombOp; Guint flags, mmr, templ, enableSkip, combOp; Guint gridW, gridH, stepX, stepY, patW, patH; int atx[4], aty[4]; int gridX, gridY, xx, yy, bit, j; Guint bpp, m, n, i; // region segment info field if (!readULong(&w) || !readULong(&h) || !readULong(&x) || !readULong(&y) || !readUByte(&segInfoFlags)) { goto eofError; } extCombOp = segInfoFlags & 7; // rest of the halftone region header if (!readUByte(&flags)) { goto eofError; } mmr = flags & 1; templ = (flags >> 1) & 3; enableSkip = (flags >> 3) & 1; combOp = (flags >> 4) & 7; if (!readULong(&gridW) || !readULong(&gridH) || !readLong(&gridX) || !readLong(&gridY) || !readUWord(&stepX) || !readUWord(&stepY)) { goto eofError; } if (w == 0 || h == 0 || w >= INT_MAX / h) { error(errSyntaxError, getPos(), "Bad bitmap size in JBIG2 halftone segment"); return; } if (gridH == 0 || gridW >= INT_MAX / gridH) { error(errSyntaxError, getPos(), "Bad grid size in JBIG2 halftone segment"); return; } // get pattern dictionary if (nRefSegs != 1) { error(errSyntaxError, getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); return; } if (!(seg = findSegment(refSegs[0])) || seg->getType() != jbig2SegPatternDict) { error(errSyntaxError, getPos(), "Bad symbol dictionary reference in JBIG2 halftone segment"); return; } patternDict = (JBIG2PatternDict *)seg; i = patternDict->getSize(); if (i <= 1) { bpp = 0; } else { --i; bpp = 0; // i = floor((size-1) / 2^bpp) while (i > 0) { ++bpp; i >>= 1; } } patW = patternDict->getBitmap(0)->getWidth(); patH = patternDict->getBitmap(0)->getHeight(); // set up the arithmetic decoder if (!mmr) { resetGenericStats(templ, NULL); arithDecoder->start(); } // allocate the bitmap bitmap = new JBIG2Bitmap(segNum, w, h); if (flags & 0x80) { // HDEFPIXEL bitmap->clearToOne(); } else { bitmap->clearToZero(); } // compute the skip bitmap skipBitmap = NULL; if (enableSkip) { skipBitmap = new JBIG2Bitmap(0, gridW, gridH); skipBitmap->clearToZero(); for (m = 0; m < gridH; ++m) { for (n = 0; n < gridW; ++n) { xx = gridX + m * stepY + n * stepX; yy = gridY + m * stepX - n * stepY; if (((xx + (int)patW) >> 8) <= 0 || (xx >> 8) >= (int)w || ((yy + (int)patH) >> 8) <= 0 || (yy >> 8) >= (int)h) { skipBitmap->setPixel(n, m); } } } } // read the gray-scale image grayImg = (Guint *)gmallocn(gridW * gridH, sizeof(Guint)); memset(grayImg, 0, gridW * gridH * sizeof(Guint)); atx[0] = templ <= 1 ? 3 : 2; aty[0] = -1; atx[1] = -3; aty[1] = -1; atx[2] = 2; aty[2] = -2; atx[3] = -2; aty[3] = -2; for (j = bpp - 1; j >= 0; --j) { grayBitmap = readGenericBitmap(mmr, gridW, gridH, templ, gFalse, enableSkip, skipBitmap, atx, aty, -1); i = 0; for (m = 0; m < gridH; ++m) { for (n = 0; n < gridW; ++n) { bit = grayBitmap->getPixel(n, m) ^ (grayImg[i] & 1); grayImg[i] = (grayImg[i] << 1) | bit; ++i; } } delete grayBitmap; } // decode the image i = 0; for (m = 0; m < gridH; ++m) { xx = gridX + m * stepY; yy = gridY + m * stepX; for (n = 0; n < gridW; ++n) { if (!(enableSkip && skipBitmap->getPixel(n, m))) { patternBitmap = patternDict->getBitmap(grayImg[i]); bitmap->combine(patternBitmap, xx >> 8, yy >> 8, combOp); } xx += stepX; yy -= stepY; ++i; } } gfree(grayImg); if (skipBitmap) { delete skipBitmap; } // combine the region bitmap into the page bitmap if (imm) { if (pageH == 0xffffffff && y + h > curPageH) { pageBitmap->expand(y + h, pageDefPixel); } pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; // store the region bitmap } else { segments->append(bitmap); } return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } void JBIG2Stream::readGenericRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length) { JBIG2Bitmap *bitmap; Guint w, h, x, y, segInfoFlags, extCombOp, rowCount; Guint flags, mmr, templ, tpgdOn; int atx[4], aty[4]; // region segment info field if (!readULong(&w) || !readULong(&h) || !readULong(&x) || !readULong(&y) || !readUByte(&segInfoFlags)) { goto eofError; } extCombOp = segInfoFlags & 7; // rest of the generic region segment header if (!readUByte(&flags)) { goto eofError; } mmr = flags & 1; templ = (flags >> 1) & 3; tpgdOn = (flags >> 3) & 1; // AT flags if (!mmr) { if (templ == 0) { if (!readByte(&atx[0]) || !readByte(&aty[0]) || !readByte(&atx[1]) || !readByte(&aty[1]) || !readByte(&atx[2]) || !readByte(&aty[2]) || !readByte(&atx[3]) || !readByte(&aty[3])) { goto eofError; } } else { if (!readByte(&atx[0]) || !readByte(&aty[0])) { goto eofError; } } } // set up the arithmetic decoder if (!mmr) { resetGenericStats(templ, NULL); arithDecoder->start(); } // read the bitmap bitmap = readGenericBitmap(mmr, w, h, templ, tpgdOn, gFalse, NULL, atx, aty, mmr ? length - 18 : 0); // combine the region bitmap into the page bitmap if (imm) { if (pageH == 0xffffffff && y + h > curPageH) { pageBitmap->expand(y + h, pageDefPixel); } pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; // store the region bitmap } else { bitmap->setSegNum(segNum); segments->append(bitmap); } // immediate generic segments can have an unspecified length, in // which case, a row count is stored at the end of the segment if (imm && length == 0xffffffff) { readULong(&rowCount); } return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } inline void JBIG2Stream::mmrAddPixels(int a1, int blackPixels, int *codingLine, int *a0i, int w) { if (a1 > codingLine[*a0i]) { if (a1 > w) { error(errSyntaxError, getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1); a1 = w; } if ((*a0i & 1) ^ blackPixels) { ++*a0i; } codingLine[*a0i] = a1; } } inline void JBIG2Stream::mmrAddPixelsNeg(int a1, int blackPixels, int *codingLine, int *a0i, int w) { if (a1 > codingLine[*a0i]) { if (a1 > w) { error(errSyntaxError, getPos(), "JBIG2 MMR row is wrong length ({0:d})", a1); a1 = w; } if ((*a0i & 1) ^ blackPixels) { ++*a0i; } codingLine[*a0i] = a1; } else if (a1 < codingLine[*a0i]) { if (a1 < 0) { error(errSyntaxError, getPos(), "Invalid JBIG2 MMR code"); a1 = 0; } while (*a0i > 0 && a1 <= codingLine[*a0i - 1]) { --*a0i; } codingLine[*a0i] = a1; } } JBIG2Bitmap *JBIG2Stream::readGenericBitmap(GBool mmr, int w, int h, int templ, GBool tpgdOn, GBool useSkip, JBIG2Bitmap *skip, int *atx, int *aty, int mmrDataLength) { JBIG2Bitmap *bitmap; GBool ltp; Guint ltpCX, cx, cx0, cx1, cx2; int *refLine, *codingLine; int code1, code2, code3; Guchar *p0, *p1, *p2, *pp; Guchar *atP0, *atP1, *atP2, *atP3; Guint buf0, buf1, buf2; Guint atBuf0, atBuf1, atBuf2, atBuf3; int atShift0, atShift1, atShift2, atShift3; Guchar mask; int x, y, x0, x1, a0i, b1i, blackPixels, pix, i; bitmap = new JBIG2Bitmap(0, w, h); bitmap->clearToZero(); //----- MMR decode if (mmr) { mmrDecoder->reset(); if (w > INT_MAX - 2) { error(errSyntaxError, getPos(), "Bad width in JBIG2 generic bitmap"); // force a call to gmalloc(-1), which will throw an exception w = -3; } // 0 <= codingLine[0] < codingLine[1] < ... < codingLine[n] = w // ---> max codingLine size = w + 1 // refLine has one extra guard entry at the end // ---> max refLine size = w + 2 codingLine = (int *)gmallocn(w + 1, sizeof(int)); refLine = (int *)gmallocn(w + 2, sizeof(int)); codingLine[0] = w; for (y = 0; y < h; ++y) { // copy coding line to ref line for (i = 0; codingLine[i] < w; ++i) { refLine[i] = codingLine[i]; } refLine[i++] = w; refLine[i] = w; // decode a line codingLine[0] = 0; a0i = 0; b1i = 0; blackPixels = 0; // invariant: // refLine[b1i-1] <= codingLine[a0i] < refLine[b1i] < refLine[b1i+1] <= w // exception at left edge: // codingLine[a0i = 0] = refLine[b1i = 0] = 0 is possible // exception at right edge: // refLine[b1i] = refLine[b1i+1] = w is possible while (codingLine[a0i] < w) { code1 = mmrDecoder->get2DCode(); switch (code1) { case twoDimPass: mmrAddPixels(refLine[b1i + 1], blackPixels, codingLine, &a0i, w); if (refLine[b1i + 1] < w) { b1i += 2; } break; case twoDimHoriz: code1 = code2 = 0; if (blackPixels) { do { code1 += code3 = mmrDecoder->getBlackCode(); } while (code3 >= 64); do { code2 += code3 = mmrDecoder->getWhiteCode(); } while (code3 >= 64); } else { do { code1 += code3 = mmrDecoder->getWhiteCode(); } while (code3 >= 64); do { code2 += code3 = mmrDecoder->getBlackCode(); } while (code3 >= 64); } mmrAddPixels(codingLine[a0i] + code1, blackPixels, codingLine, &a0i, w); if (codingLine[a0i] < w) { mmrAddPixels(codingLine[a0i] + code2, blackPixels ^ 1, codingLine, &a0i, w); } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } break; case twoDimVertR3: mmrAddPixels(refLine[b1i] + 3, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVertR2: mmrAddPixels(refLine[b1i] + 2, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVertR1: mmrAddPixels(refLine[b1i] + 1, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVert0: mmrAddPixels(refLine[b1i], blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { ++b1i; while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVertL3: mmrAddPixelsNeg(refLine[b1i] - 3, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVertL2: mmrAddPixelsNeg(refLine[b1i] - 2, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case twoDimVertL1: mmrAddPixelsNeg(refLine[b1i] - 1, blackPixels, codingLine, &a0i, w); blackPixels ^= 1; if (codingLine[a0i] < w) { if (b1i > 0) { --b1i; } else { ++b1i; } while (refLine[b1i] <= codingLine[a0i] && refLine[b1i] < w) { b1i += 2; } } break; case EOF: mmrAddPixels(w, 0, codingLine, &a0i, w); break; default: error(errSyntaxError, getPos(), "Illegal code in JBIG2 MMR bitmap data"); mmrAddPixels(w, 0, codingLine, &a0i, w); break; } } // convert the run lengths to a bitmap line i = 0; while (1) { for (x = codingLine[i]; x < codingLine[i+1]; ++x) { bitmap->setPixel(x, y); } if (codingLine[i+1] >= w || codingLine[i+2] >= w) { break; } i += 2; } } if (mmrDataLength >= 0) { mmrDecoder->skipTo(mmrDataLength); } else { if (mmrDecoder->get24Bits() != 0x001001) { error(errSyntaxError, getPos(), "Missing EOFB in JBIG2 MMR bitmap data"); } } gfree(refLine); gfree(codingLine); //----- arithmetic decode } else { // set up the typical row context ltpCX = 0; // make gcc happy if (tpgdOn) { switch (templ) { case 0: ltpCX = 0x3953; // 001 11001 0101 0011 break; case 1: ltpCX = 0x079a; // 0011 11001 101 0 break; case 2: ltpCX = 0x0e3; // 001 1100 01 1 break; case 3: ltpCX = 0x18a; // 01100 0101 1 break; } } ltp = 0; cx = cx0 = cx1 = cx2 = 0; // make gcc happy for (y = 0; y < h; ++y) { // check for a "typical" (duplicate) row if (tpgdOn) { if (arithDecoder->decodeBit(ltpCX, genericRegionStats)) { ltp = !ltp; } if (ltp) { if (y > 0) { bitmap->duplicateRow(y, y-1); } continue; } } switch (templ) { case 0: // set up the context p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize(); buf2 = *p2++ << 8; if (y >= 1) { p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize(); buf1 = *p1++ << 8; if (y >= 2) { p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize(); buf0 = *p0++ << 8; } else { p0 = NULL; buf0 = 0; } } else { p1 = p0 = NULL; buf1 = buf0 = 0; } if (atx[0] >= -8 && atx[0] <= 8 && atx[1] >= -8 && atx[1] <= 8 && atx[2] >= -8 && atx[2] <= 8 && atx[3] >= -8 && atx[3] <= 8) { // set up the adaptive context if (y + aty[0] >= 0) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { atP0 = NULL; atBuf0 = 0; } atShift0 = 15 - atx[0]; if (y + aty[1] >= 0) { atP1 = bitmap->getDataPtr() + (y + aty[1]) * bitmap->getLineSize(); atBuf1 = *atP1++ << 8; } else { atP1 = NULL; atBuf1 = 0; } atShift1 = 15 - atx[1]; if (y + aty[2] >= 0) { atP2 = bitmap->getDataPtr() + (y + aty[2]) * bitmap->getLineSize(); atBuf2 = *atP2++ << 8; } else { atP2 = NULL; atBuf2 = 0; } atShift2 = 15 - atx[2]; if (y + aty[3] >= 0) { atP3 = bitmap->getDataPtr() + (y + aty[3]) * bitmap->getLineSize(); atBuf3 = *atP3++ << 8; } else { atP3 = NULL; atBuf3 = 0; } atShift3 = 15 - atx[3]; // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; if (atP0) { atBuf0 |= *atP0++; } if (atP1) { atBuf1 |= *atP1++; } if (atP2) { atBuf2 |= *atP2++; } if (atP3) { atBuf3 |= *atP3++; } } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 14) & 0x07; cx1 = (buf1 >> 13) & 0x1f; cx2 = (buf2 >> 16) & 0x0f; cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | (((atBuf0 >> atShift0) & 1) << 3) | (((atBuf1 >> atShift1) & 1) << 2) | (((atBuf2 >> atShift2) & 1) << 1) | ((atBuf3 >> atShift3) & 1); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; if (aty[0] == 0) { atBuf0 |= 0x8000; } if (aty[1] == 0) { atBuf1 |= 0x8000; } if (aty[2] == 0) { atBuf2 |= 0x8000; } if (aty[3] == 0) { atBuf3 |= 0x8000; } } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; atBuf0 <<= 1; atBuf1 <<= 1; atBuf2 <<= 1; atBuf3 <<= 1; } } } else { // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 14) & 0x07; cx1 = (buf1 >> 13) & 0x1f; cx2 = (buf2 >> 16) & 0x0f; cx = (cx0 << 13) | (cx1 << 8) | (cx2 << 4) | (bitmap->getPixel(x + atx[0], y + aty[0]) << 3) | (bitmap->getPixel(x + atx[1], y + aty[1]) << 2) | (bitmap->getPixel(x + atx[2], y + aty[2]) << 1) | bitmap->getPixel(x + atx[3], y + aty[3]); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; } } } break; case 1: // set up the context p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize(); buf2 = *p2++ << 8; if (y >= 1) { p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize(); buf1 = *p1++ << 8; if (y >= 2) { p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize(); buf0 = *p0++ << 8; } else { p0 = NULL; buf0 = 0; } } else { p1 = p0 = NULL; buf1 = buf0 = 0; } if (atx[0] >= -8 && atx[0] <= 8) { // set up the adaptive context if (y + aty[0] >= 0) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { atP0 = NULL; atBuf0 = 0; } atShift0 = 15 - atx[0]; // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; if (atP0) { atBuf0 |= *atP0++; } } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 13) & 0x0f; cx1 = (buf1 >> 13) & 0x1f; cx2 = (buf2 >> 16) & 0x07; cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | ((atBuf0 >> atShift0) & 1); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; if (aty[0] == 0) { atBuf0 |= 0x8000; } } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; atBuf0 <<= 1; } } } else { // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 13) & 0x0f; cx1 = (buf1 >> 13) & 0x1f; cx2 = (buf2 >> 16) & 0x07; cx = (cx0 << 9) | (cx1 << 4) | (cx2 << 1) | bitmap->getPixel(x + atx[0], y + aty[0]); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; } } } break; case 2: // set up the context p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize(); buf2 = *p2++ << 8; if (y >= 1) { p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize(); buf1 = *p1++ << 8; if (y >= 2) { p0 = bitmap->getDataPtr() + (y - 2) * bitmap->getLineSize(); buf0 = *p0++ << 8; } else { p0 = NULL; buf0 = 0; } } else { p1 = p0 = NULL; buf1 = buf0 = 0; } if (atx[0] >= -8 && atx[0] <= 8) { // set up the adaptive context if (y + aty[0] >= 0) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { atP0 = NULL; atBuf0 = 0; } atShift0 = 15 - atx[0]; // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; if (atP0) { atBuf0 |= *atP0++; } } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 14) & 0x07; cx1 = (buf1 >> 14) & 0x0f; cx2 = (buf2 >> 16) & 0x03; cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | ((atBuf0 >> atShift0) & 1); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; if (aty[0] == 0) { atBuf0 |= 0x8000; } } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; atBuf0 <<= 1; } } } else { // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p0) { buf0 |= *p0++; } if (p1) { buf1 |= *p1++; } buf2 |= *p2++; } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx0 = (buf0 >> 14) & 0x07; cx1 = (buf1 >> 14) & 0x0f; cx2 = (buf2 >> 16) & 0x03; cx = (cx0 << 7) | (cx1 << 3) | (cx2 << 1) | bitmap->getPixel(x + atx[0], y + aty[0]); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; } } // update the context buf0 <<= 1; buf1 <<= 1; buf2 <<= 1; } } } break; case 3: // set up the context p2 = pp = bitmap->getDataPtr() + y * bitmap->getLineSize(); buf2 = *p2++ << 8; if (y >= 1) { p1 = bitmap->getDataPtr() + (y - 1) * bitmap->getLineSize(); buf1 = *p1++ << 8; } else { p1 = NULL; buf1 = 0; } if (atx[0] >= -8 && atx[0] <= 8) { // set up the adaptive context if (y + aty[0] >= 0) { atP0 = bitmap->getDataPtr() + (y + aty[0]) * bitmap->getLineSize(); atBuf0 = *atP0++ << 8; } else { atP0 = NULL; atBuf0 = 0; } atShift0 = 15 - atx[0]; // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p1) { buf1 |= *p1++; } buf2 |= *p2++; if (atP0) { atBuf0 |= *atP0++; } } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx1 = (buf1 >> 14) & 0x1f; cx2 = (buf2 >> 16) & 0x0f; cx = (cx1 << 5) | (cx2 << 1) | ((atBuf0 >> atShift0) & 1); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; if (aty[0] == 0) { atBuf0 |= 0x8000; } } } // update the context buf1 <<= 1; buf2 <<= 1; atBuf0 <<= 1; } } } else { // decode the row for (x0 = 0, x = 0; x0 < w; x0 += 8, ++pp) { if (x0 + 8 < w) { if (p1) { buf1 |= *p1++; } buf2 |= *p2++; } for (x1 = 0, mask = 0x80; x1 < 8 && x < w; ++x1, ++x, mask >>= 1) { // build the context cx1 = (buf1 >> 14) & 0x1f; cx2 = (buf2 >> 16) & 0x0f; cx = (cx1 << 5) | (cx2 << 1) | bitmap->getPixel(x + atx[0], y + aty[0]); // check for a skipped pixel if (!(useSkip && skip->getPixel(x, y))) { // decode the pixel if ((pix = arithDecoder->decodeBit(cx, genericRegionStats))) { *pp |= mask; buf2 |= 0x8000; } } // update the context buf1 <<= 1; buf2 <<= 1; } } } break; } } } return bitmap; } void JBIG2Stream::readGenericRefinementRegionSeg(Guint segNum, GBool imm, GBool lossless, Guint length, Guint *refSegs, Guint nRefSegs) { JBIG2Bitmap *bitmap, *refBitmap; Guint w, h, x, y, segInfoFlags, extCombOp; Guint flags, templ, tpgrOn; int atx[2], aty[2]; JBIG2Segment *seg; // region segment info field if (!readULong(&w) || !readULong(&h) || !readULong(&x) || !readULong(&y) || !readUByte(&segInfoFlags)) { goto eofError; } extCombOp = segInfoFlags & 7; // rest of the generic refinement region segment header if (!readUByte(&flags)) { goto eofError; } templ = flags & 1; tpgrOn = (flags >> 1) & 1; // AT flags if (!templ) { if (!readByte(&atx[0]) || !readByte(&aty[0]) || !readByte(&atx[1]) || !readByte(&aty[1])) { goto eofError; } } // resize the page bitmap if needed if (nRefSegs == 0 || imm) { if (pageH == 0xffffffff && y + h > curPageH) { pageBitmap->expand(y + h, pageDefPixel); } } // get referenced bitmap if (nRefSegs > 1) { error(errSyntaxError, getPos(), "Bad reference in JBIG2 generic refinement segment"); return; } if (nRefSegs == 1) { if (!(seg = findSegment(refSegs[0])) || seg->getType() != jbig2SegBitmap) { error(errSyntaxError, getPos(), "Bad bitmap reference in JBIG2 generic refinement segment"); return; } refBitmap = (JBIG2Bitmap *)seg; } else { refBitmap = pageBitmap->getSlice(x, y, w, h); } // set up the arithmetic decoder resetRefinementStats(templ, NULL); arithDecoder->start(); // read bitmap = readGenericRefinementRegion(w, h, templ, tpgrOn, refBitmap, 0, 0, atx, aty); // combine the region bitmap into the page bitmap if (imm) { pageBitmap->combine(bitmap, x, y, extCombOp); delete bitmap; // store the region bitmap } else { bitmap->setSegNum(segNum); segments->append(bitmap); } // delete the referenced bitmap if (nRefSegs == 1) { discardSegment(refSegs[0]); } else { delete refBitmap; } return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } JBIG2Bitmap *JBIG2Stream::readGenericRefinementRegion(int w, int h, int templ, GBool tpgrOn, JBIG2Bitmap *refBitmap, int refDX, int refDY, int *atx, int *aty) { JBIG2Bitmap *bitmap; GBool ltp; Guint ltpCX, cx, cx0, cx2, cx3, cx4, tpgrCX0, tpgrCX1, tpgrCX2; JBIG2BitmapPtr cxPtr0, cxPtr1, cxPtr2, cxPtr3, cxPtr4, cxPtr5, cxPtr6; JBIG2BitmapPtr tpgrCXPtr0, tpgrCXPtr1, tpgrCXPtr2; int x, y, pix; bitmap = new JBIG2Bitmap(0, w, h); bitmap->clearToZero(); // set up the typical row context if (templ) { ltpCX = 0x008; } else { ltpCX = 0x0010; } ltp = 0; for (y = 0; y < h; ++y) { if (templ) { // set up the context bitmap->getPixelPtr(0, y-1, &cxPtr0); cx0 = bitmap->nextPixel(&cxPtr0); bitmap->getPixelPtr(-1, y, &cxPtr1); refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); cx3 = refBitmap->nextPixel(&cxPtr3); cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); refBitmap->getPixelPtr(-refDX, y+1-refDY, &cxPtr4); cx4 = refBitmap->nextPixel(&cxPtr4); // set up the typical prediction context tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy if (tpgrOn) { refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); } else { tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0; tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0; } for (x = 0; x < w; ++x) { // update the context cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 7; cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 3; if (tpgrOn) { // update the typical predictor context tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; // check for a "typical" pixel if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { ltp = !ltp; } if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { bitmap->clearPixel(x, y); continue; } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { bitmap->setPixel(x, y); continue; } } // build the context cx = (cx0 << 7) | (bitmap->nextPixel(&cxPtr1) << 6) | (refBitmap->nextPixel(&cxPtr2) << 5) | (cx3 << 2) | cx4; // decode the pixel if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { bitmap->setPixel(x, y); } } } else { // set up the context bitmap->getPixelPtr(0, y-1, &cxPtr0); cx0 = bitmap->nextPixel(&cxPtr0); bitmap->getPixelPtr(-1, y, &cxPtr1); refBitmap->getPixelPtr(-refDX, y-1-refDY, &cxPtr2); cx2 = refBitmap->nextPixel(&cxPtr2); refBitmap->getPixelPtr(-1-refDX, y-refDY, &cxPtr3); cx3 = refBitmap->nextPixel(&cxPtr3); cx3 = (cx3 << 1) | refBitmap->nextPixel(&cxPtr3); refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &cxPtr4); cx4 = refBitmap->nextPixel(&cxPtr4); cx4 = (cx4 << 1) | refBitmap->nextPixel(&cxPtr4); bitmap->getPixelPtr(atx[0], y+aty[0], &cxPtr5); refBitmap->getPixelPtr(atx[1]-refDX, y+aty[1]-refDY, &cxPtr6); // set up the typical prediction context tpgrCX0 = tpgrCX1 = tpgrCX2 = 0; // make gcc happy if (tpgrOn) { refBitmap->getPixelPtr(-1-refDX, y-1-refDY, &tpgrCXPtr0); tpgrCX0 = refBitmap->nextPixel(&tpgrCXPtr0); tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); tpgrCX0 = (tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0); refBitmap->getPixelPtr(-1-refDX, y-refDY, &tpgrCXPtr1); tpgrCX1 = refBitmap->nextPixel(&tpgrCXPtr1); tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); tpgrCX1 = (tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1); refBitmap->getPixelPtr(-1-refDX, y+1-refDY, &tpgrCXPtr2); tpgrCX2 = refBitmap->nextPixel(&tpgrCXPtr2); tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); tpgrCX2 = (tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2); } else { tpgrCXPtr0.p = tpgrCXPtr1.p = tpgrCXPtr2.p = NULL; // make gcc happy tpgrCXPtr0.shift = tpgrCXPtr1.shift = tpgrCXPtr2.shift = 0; tpgrCXPtr0.x = tpgrCXPtr1.x = tpgrCXPtr2.x = 0; } for (x = 0; x < w; ++x) { // update the context cx0 = ((cx0 << 1) | bitmap->nextPixel(&cxPtr0)) & 3; cx2 = ((cx2 << 1) | refBitmap->nextPixel(&cxPtr2)) & 3; cx3 = ((cx3 << 1) | refBitmap->nextPixel(&cxPtr3)) & 7; cx4 = ((cx4 << 1) | refBitmap->nextPixel(&cxPtr4)) & 7; if (tpgrOn) { // update the typical predictor context tpgrCX0 = ((tpgrCX0 << 1) | refBitmap->nextPixel(&tpgrCXPtr0)) & 7; tpgrCX1 = ((tpgrCX1 << 1) | refBitmap->nextPixel(&tpgrCXPtr1)) & 7; tpgrCX2 = ((tpgrCX2 << 1) | refBitmap->nextPixel(&tpgrCXPtr2)) & 7; // check for a "typical" pixel if (arithDecoder->decodeBit(ltpCX, refinementRegionStats)) { ltp = !ltp; } if (tpgrCX0 == 0 && tpgrCX1 == 0 && tpgrCX2 == 0) { bitmap->clearPixel(x, y); continue; } else if (tpgrCX0 == 7 && tpgrCX1 == 7 && tpgrCX2 == 7) { bitmap->setPixel(x, y); continue; } } // build the context cx = (cx0 << 11) | (bitmap->nextPixel(&cxPtr1) << 10) | (cx2 << 8) | (cx3 << 5) | (cx4 << 2) | (bitmap->nextPixel(&cxPtr5) << 1) | refBitmap->nextPixel(&cxPtr6); // decode the pixel if ((pix = arithDecoder->decodeBit(cx, refinementRegionStats))) { bitmap->setPixel(x, y); } } } } return bitmap; } void JBIG2Stream::readPageInfoSeg(Guint length) { Guint xRes, yRes, flags, striping; if (!readULong(&pageW) || !readULong(&pageH) || !readULong(&xRes) || !readULong(&yRes) || !readUByte(&flags) || !readUWord(&striping)) { goto eofError; } pageDefPixel = (flags >> 2) & 1; defCombOp = (flags >> 3) & 3; // allocate the page bitmap if (pageH == 0xffffffff) { curPageH = striping & 0x7fff; } else { curPageH = pageH; } pageBitmap = new JBIG2Bitmap(0, pageW, curPageH); // default pixel value if (pageDefPixel) { pageBitmap->clearToOne(); } else { pageBitmap->clearToZero(); } return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } void JBIG2Stream::readEndOfStripeSeg(Guint length) { Guint i; // skip the segment for (i = 0; i < length; ++i) { if (curStr->getChar() == EOF) { break; } ++byteCounter; } } void JBIG2Stream::readProfilesSeg(Guint length) { Guint i; // skip the segment for (i = 0; i < length; ++i) { if (curStr->getChar() == EOF) { break; } ++byteCounter; } } void JBIG2Stream::readCodeTableSeg(Guint segNum, Guint length) { JBIG2HuffmanTable *huffTab; Guint flags, oob, prefixBits, rangeBits; int lowVal, highVal, val; Guint huffTabSize, i; if (!readUByte(&flags) || !readLong(&lowVal) || !readLong(&highVal)) { goto eofError; } oob = flags & 1; prefixBits = ((flags >> 1) & 7) + 1; rangeBits = ((flags >> 4) & 7) + 1; huffDecoder->reset(); huffTabSize = 8; huffTab = (JBIG2HuffmanTable *) gmallocn(huffTabSize, sizeof(JBIG2HuffmanTable)); i = 0; val = lowVal; while (val < highVal) { if (i == huffTabSize) { huffTabSize *= 2; huffTab = (JBIG2HuffmanTable *) greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = val; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); huffTab[i].rangeLen = huffDecoder->readBits(rangeBits); val += 1 << huffTab[i].rangeLen; ++i; } if (i + oob + 3 > huffTabSize) { huffTabSize = i + oob + 3; huffTab = (JBIG2HuffmanTable *) greallocn(huffTab, huffTabSize, sizeof(JBIG2HuffmanTable)); } huffTab[i].val = lowVal - 1; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); huffTab[i].rangeLen = jbig2HuffmanLOW; ++i; huffTab[i].val = highVal; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); huffTab[i].rangeLen = 32; ++i; if (oob) { huffTab[i].val = 0; huffTab[i].prefixLen = huffDecoder->readBits(prefixBits); huffTab[i].rangeLen = jbig2HuffmanOOB; ++i; } huffTab[i].val = 0; huffTab[i].prefixLen = 0; huffTab[i].rangeLen = jbig2HuffmanEOT; huffDecoder->buildTable(huffTab, i); // create and store the new table segment segments->append(new JBIG2CodeTable(segNum, huffTab)); return; eofError: error(errSyntaxError, getPos(), "Unexpected EOF in JBIG2 stream"); } void JBIG2Stream::readExtensionSeg(Guint length) { Guint i; // skip the segment for (i = 0; i < length; ++i) { if (curStr->getChar() == EOF) { break; } ++byteCounter; } } JBIG2Segment *JBIG2Stream::findSegment(Guint segNum) { JBIG2Segment *seg; int i; for (i = 0; i < globalSegments->getLength(); ++i) { seg = (JBIG2Segment *)globalSegments->get(i); if (seg->getSegNum() == segNum) { return seg; } } for (i = 0; i < segments->getLength(); ++i) { seg = (JBIG2Segment *)segments->get(i); if (seg->getSegNum() == segNum) { return seg; } } return NULL; } void JBIG2Stream::discardSegment(Guint segNum) { JBIG2Segment *seg; int i; for (i = 0; i < globalSegments->getLength(); ++i) { seg = (JBIG2Segment *)globalSegments->get(i); if (seg->getSegNum() == segNum) { globalSegments->del(i); return; } } for (i = 0; i < segments->getLength(); ++i) { seg = (JBIG2Segment *)segments->get(i); if (seg->getSegNum() == segNum) { segments->del(i); return; } } } void JBIG2Stream::resetGenericStats(Guint templ, JArithmeticDecoderStats *prevStats) { int size; size = contextSize[templ]; if (prevStats && prevStats->getContextSize() == size) { if (genericRegionStats->getContextSize() == size) { genericRegionStats->copyFrom(prevStats); } else { delete genericRegionStats; genericRegionStats = prevStats->copy(); } } else { if (genericRegionStats->getContextSize() == size) { genericRegionStats->reset(); } else { delete genericRegionStats; genericRegionStats = new JArithmeticDecoderStats(1 << size); } } } void JBIG2Stream::resetRefinementStats(Guint templ, JArithmeticDecoderStats *prevStats) { int size; size = refContextSize[templ]; if (prevStats && prevStats->getContextSize() == size) { if (refinementRegionStats->getContextSize() == size) { refinementRegionStats->copyFrom(prevStats); } else { delete refinementRegionStats; refinementRegionStats = prevStats->copy(); } } else { if (refinementRegionStats->getContextSize() == size) { refinementRegionStats->reset(); } else { delete refinementRegionStats; refinementRegionStats = new JArithmeticDecoderStats(1 << size); } } } void JBIG2Stream::resetIntStats(int symCodeLen) { iadhStats->reset(); iadwStats->reset(); iaexStats->reset(); iaaiStats->reset(); iadtStats->reset(); iaitStats->reset(); iafsStats->reset(); iadsStats->reset(); iardxStats->reset(); iardyStats->reset(); iardwStats->reset(); iardhStats->reset(); iariStats->reset(); if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) { iaidStats->reset(); } else { delete iaidStats; iaidStats = new JArithmeticDecoderStats(1 << (symCodeLen + 1)); } } GBool JBIG2Stream::readUByte(Guint *x) { int c0; if ((c0 = curStr->getChar()) == EOF) { return gFalse; } ++byteCounter; *x = (Guint)c0; return gTrue; } GBool JBIG2Stream::readByte(int *x) { int c0; if ((c0 = curStr->getChar()) == EOF) { return gFalse; } ++byteCounter; *x = c0; if (c0 & 0x80) { *x |= -1 - 0xff; } return gTrue; } GBool JBIG2Stream::readUWord(Guint *x) { int c0, c1; if ((c0 = curStr->getChar()) == EOF || (c1 = curStr->getChar()) == EOF) { return gFalse; } byteCounter += 2; *x = (Guint)((c0 << 8) | c1); return gTrue; } GBool JBIG2Stream::readULong(Guint *x) { int c0, c1, c2, c3; if ((c0 = curStr->getChar()) == EOF || (c1 = curStr->getChar()) == EOF || (c2 = curStr->getChar()) == EOF || (c3 = curStr->getChar()) == EOF) { return gFalse; } byteCounter += 4; *x = (Guint)((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); return gTrue; } GBool JBIG2Stream::readLong(int *x) { int c0, c1, c2, c3; if ((c0 = curStr->getChar()) == EOF || (c1 = curStr->getChar()) == EOF || (c2 = curStr->getChar()) == EOF || (c3 = curStr->getChar()) == EOF) { return gFalse; } byteCounter += 4; *x = ((c0 << 24) | (c1 << 16) | (c2 << 8) | c3); if (c0 & 0x80) { *x |= -1 - (int)0xffffffff; } return gTrue; } xpdf-3.03/xpdf/NameToCharCode.h0000644000076400007640000000132611622305345015603 0ustar dereknderekn//======================================================================== // // NameToCharCode.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef NAMETOCHARCODE_H #define NAMETOCHARCODE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "CharTypes.h" struct NameToCharCodeEntry; //------------------------------------------------------------------------ class NameToCharCode { public: NameToCharCode(); ~NameToCharCode(); void add(const char *name, CharCode c); CharCode lookup(const char *name); private: int hash(const char *name); NameToCharCodeEntry *tab; int size; int len; }; #endif xpdf-3.03/xpdf/PSOutputDev.cc0000644000076400007640000053743711622305345015410 0ustar dereknderekn//======================================================================== // // PSOutputDev.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "GString.h" #include "GList.h" #include "GHash.h" #include "config.h" #include "GlobalParams.h" #include "Object.h" #include "Error.h" #include "Function.h" #include "Gfx.h" #include "GfxState.h" #include "GfxFont.h" #include "UnicodeMap.h" #include "FoFiType1C.h" #include "FoFiTrueType.h" #include "Catalog.h" #include "Page.h" #include "Stream.h" #include "Annot.h" #include "PDFDoc.h" #include "XRef.h" #include "PreScanOutputDev.h" #include "CharCodeToUnicode.h" #if HAVE_SPLASH # include "Splash.h" # include "SplashBitmap.h" # include "SplashOutputDev.h" #endif #include "PSOutputDev.h" #ifdef MACOS // needed for setting type/creator of MacOS files #include "ICSupport.h" #endif // the MSVC math.h doesn't define this #ifndef M_PI #define M_PI 3.14159265358979323846 #endif //------------------------------------------------------------------------ // Max size of a slice when rasterizing pages, in pixels. #define rasterizationSliceSize 20000000 //------------------------------------------------------------------------ // PostScript prolog and setup //------------------------------------------------------------------------ // The '~' escapes mark prolog code that is emitted only in certain // levels: // // ~[123][sn] // ^ ^----- s=psLevel*Sep, n=psLevel* // +----- 1=psLevel1*, 2=psLevel2*, 3=psLevel3* static const char *prolog[] = { "/xpdf 75 dict def xpdf begin", "% PDF special state", "/pdfDictSize 15 def", "~1sn", "/pdfStates 64 array def", " 0 1 63 {", " pdfStates exch pdfDictSize dict", " dup /pdfStateIdx 3 index put", " put", " } for", "~123sn", "/pdfSetup {", " /setpagedevice where {", " pop 2 dict begin", " /Policies 1 dict dup begin /PageSize 6 def end def", " { /Duplex true def } if", " currentdict end setpagedevice", " } {", " pop", " } ifelse", "} def", "/pdfSetupPaper {", " 2 array astore", " /setpagedevice where {", " pop 2 dict begin", " /PageSize exch def", " /ImagingBBox null def", " currentdict end setpagedevice", " } {", " pop", " } ifelse", "} def", "~1sn", "/pdfOpNames [", " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke", " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender", " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath", "] def", "~123sn", "/pdfStartPage {", "~1sn", " pdfStates 0 get begin", "~23sn", " pdfDictSize dict begin", "~23n", " /pdfFillCS [] def", " /pdfFillXform {} def", " /pdfStrokeCS [] def", " /pdfStrokeXform {} def", "~1n", " /pdfFill 0 def", " /pdfStroke 0 def", "~1s", " /pdfFill [0 0 0 1] def", " /pdfStroke [0 0 0 1] def", "~23sn", " /pdfFill [0] def", " /pdfStroke [0] def", " /pdfFillOP false def", " /pdfStrokeOP false def", "~123sn", " /pdfLastFill false def", " /pdfLastStroke false def", " /pdfTextMat [1 0 0 1 0 0] def", " /pdfFontSize 0 def", " /pdfCharSpacing 0 def", " /pdfTextRender 0 def", " /pdfTextRise 0 def", " /pdfWordSpacing 0 def", " /pdfHorizScaling 1 def", " /pdfTextClipPath [] def", "} def", "/pdfEndPage { end } def", "~23s", "% separation convention operators", "/findcmykcustomcolor where {", " pop", "}{", " /findcmykcustomcolor { 5 array astore } def", "} ifelse", "/setcustomcolor where {", " pop", "}{", " /setcustomcolor {", " exch", " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", " 0 4 getinterval cvx", " [ exch /dup load exch { mul exch dup } /forall load", " /pop load dup ] cvx", " ] setcolorspace setcolor", " } def", "} ifelse", "/customcolorimage where {", " pop", "}{", " /customcolorimage {", " gsave", " [ exch /Separation exch dup 4 get exch /DeviceCMYK exch", " 0 4 getinterval", " [ exch /dup load exch { mul exch dup } /forall load", " /pop load dup ] cvx", " ] setcolorspace", " 10 dict begin", " /ImageType 1 def", " /DataSource exch def", " /ImageMatrix exch def", " /BitsPerComponent exch def", " /Height exch def", " /Width exch def", " /Decode [1 0] def", " currentdict end", " image", " grestore", " } def", "} ifelse", "~123sn", "% PDF color state", "~1n", "/g { dup /pdfFill exch def setgray", " /pdfLastFill true def /pdfLastStroke false def } def", "/G { dup /pdfStroke exch def setgray", " /pdfLastStroke true def /pdfLastFill false def } def", "/fCol {", " pdfLastFill not {", " pdfFill setgray", " /pdfLastFill true def /pdfLastStroke false def", " } if", "} def", "/sCol {", " pdfLastStroke not {", " pdfStroke setgray", " /pdfLastStroke true def /pdfLastFill false def", " } if", "} def", "~1s", "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", " /pdfLastFill true def /pdfLastStroke false def } def", "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", " /pdfLastStroke true def /pdfLastFill false def } def", "/fCol {", " pdfLastFill not {", " pdfFill aload pop setcmykcolor", " /pdfLastFill true def /pdfLastStroke false def", " } if", "} def", "/sCol {", " pdfLastStroke not {", " pdfStroke aload pop setcmykcolor", " /pdfLastStroke true def /pdfLastFill false def", " } if", "} def", "~23n", "/cs { /pdfFillXform exch def dup /pdfFillCS exch def", " setcolorspace } def", "/CS { /pdfStrokeXform exch def dup /pdfStrokeCS exch def", " setcolorspace } def", "/sc { pdfLastFill not { pdfFillCS setcolorspace } if", " dup /pdfFill exch def aload pop pdfFillXform setcolor", " /pdfLastFill true def /pdfLastStroke false def } def", "/SC { pdfLastStroke not { pdfStrokeCS setcolorspace } if", " dup /pdfStroke exch def aload pop pdfStrokeXform setcolor", " /pdfLastStroke true def /pdfLastFill false def } def", "/op { /pdfFillOP exch def", " pdfLastFill { pdfFillOP setoverprint } if } def", "/OP { /pdfStrokeOP exch def", " pdfLastStroke { pdfStrokeOP setoverprint } if } def", "/fCol {", " pdfLastFill not {", " pdfFillCS setcolorspace", " pdfFill aload pop pdfFillXform setcolor", " pdfFillOP setoverprint", " /pdfLastFill true def /pdfLastStroke false def", " } if", "} def", "/sCol {", " pdfLastStroke not {", " pdfStrokeCS setcolorspace", " pdfStroke aload pop pdfStrokeXform setcolor", " pdfStrokeOP setoverprint", " /pdfLastStroke true def /pdfLastFill false def", " } if", "} def", "~23s", "/k { 4 copy 4 array astore /pdfFill exch def setcmykcolor", " /pdfLastFill true def /pdfLastStroke false def } def", "/K { 4 copy 4 array astore /pdfStroke exch def setcmykcolor", " /pdfLastStroke true def /pdfLastFill false def } def", "/ck { 6 copy 6 array astore /pdfFill exch def", " findcmykcustomcolor exch setcustomcolor", " /pdfLastFill true def /pdfLastStroke false def } def", "/CK { 6 copy 6 array astore /pdfStroke exch def", " findcmykcustomcolor exch setcustomcolor", " /pdfLastStroke true def /pdfLastFill false def } def", "/op { /pdfFillOP exch def", " pdfLastFill { pdfFillOP setoverprint } if } def", "/OP { /pdfStrokeOP exch def", " pdfLastStroke { pdfStrokeOP setoverprint } if } def", "/fCol {", " pdfLastFill not {", " pdfFill aload length 4 eq {", " setcmykcolor", " }{", " findcmykcustomcolor exch setcustomcolor", " } ifelse", " pdfFillOP setoverprint", " /pdfLastFill true def /pdfLastStroke false def", " } if", "} def", "/sCol {", " pdfLastStroke not {", " pdfStroke aload length 4 eq {", " setcmykcolor", " }{", " findcmykcustomcolor exch setcustomcolor", " } ifelse", " pdfStrokeOP setoverprint", " /pdfLastStroke true def /pdfLastFill false def", " } if", "} def", "~123sn", "% build a font", "/pdfMakeFont {", " 4 3 roll findfont", " 4 2 roll matrix scale makefont", " dup length dict begin", " { 1 index /FID ne { def } { pop pop } ifelse } forall", " /Encoding exch def", " currentdict", " end", " definefont pop", "} def", "/pdfMakeFont16 {", " exch findfont", " dup length dict begin", " { 1 index /FID ne { def } { pop pop } ifelse } forall", " /WMode exch def", " currentdict", " end", " definefont pop", "} def", "~3sn", "/pdfMakeFont16L3 {", " 1 index /CIDFont resourcestatus {", " pop pop 1 index /CIDFont findresource /CIDFontType known", " } {", " false", " } ifelse", " {", " 0 eq { /Identity-H } { /Identity-V } ifelse", " exch 1 array astore composefont pop", " } {", " pdfMakeFont16", " } ifelse", "} def", "~123sn", "% graphics state operators", "~1sn", "/q {", " gsave", " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for", " pdfStates pdfStateIdx 1 add get begin", " pdfOpNames { exch def } forall", "} def", "/Q { end grestore } def", "~23sn", "/q { gsave pdfDictSize dict begin } def", "/Q {", " end grestore", " /pdfLastFill where {", " pop", " pdfLastFill {", " pdfFillOP setoverprint", " } {", " pdfStrokeOP setoverprint", " } ifelse", " } if", "} def", "~123sn", "/cm { concat } def", "/d { setdash } def", "/i { setflat } def", "/j { setlinejoin } def", "/J { setlinecap } def", "/M { setmiterlimit } def", "/w { setlinewidth } def", "% path segment operators", "/m { moveto } def", "/l { lineto } def", "/c { curveto } def", "/re { 4 2 roll moveto 1 index 0 rlineto 0 exch rlineto", " neg 0 rlineto closepath } def", "/h { closepath } def", "% path painting operators", "/S { sCol stroke } def", "/Sf { fCol stroke } def", "/f { fCol fill } def", "/f* { fCol eofill } def", "% clipping operators", "/W { clip newpath } def", "/W* { eoclip newpath } def", "/Ws { strokepath clip newpath } def", "% text state operators", "/Tc { /pdfCharSpacing exch def } def", "/Tf { dup /pdfFontSize exch def", " dup pdfHorizScaling mul exch matrix scale", " pdfTextMat matrix concatmatrix dup 4 0 put dup 5 0 put", " exch findfont exch makefont setfont } def", "/Tr { /pdfTextRender exch def } def", "/Ts { /pdfTextRise exch def } def", "/Tw { /pdfWordSpacing exch def } def", "/Tz { /pdfHorizScaling exch def } def", "% text positioning operators", "/Td { pdfTextMat transform moveto } def", "/Tm { /pdfTextMat exch def } def", "% text string operators", "/xyshow where {", " pop", " /xyshow2 {", " dup length array", " 0 2 2 index length 1 sub {", " 2 index 1 index 2 copy get 3 1 roll 1 add get", " pdfTextMat dtransform", " 4 2 roll 2 copy 6 5 roll put 1 add 3 1 roll dup 4 2 roll put", " } for", " exch pop", " xyshow", " } def", "}{", " /xyshow2 {", " currentfont /FontType get 0 eq {", " 0 2 3 index length 1 sub {", " currentpoint 4 index 3 index 2 getinterval show moveto", " 2 copy get 2 index 3 2 roll 1 add get", " pdfTextMat dtransform rmoveto", " } for", " } {", " 0 1 3 index length 1 sub {", " currentpoint 4 index 3 index 1 getinterval show moveto", " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get", " pdfTextMat dtransform rmoveto", " } for", " } ifelse", " pop pop", " } def", "} ifelse", "/cshow where {", " pop", " /xycp {", // xycharpath " 0 3 2 roll", " {", " pop pop currentpoint 3 2 roll", " 1 string dup 0 4 3 roll put false charpath moveto", " 2 copy get 2 index 2 index 1 add get", " pdfTextMat dtransform rmoveto", " 2 add", " } exch cshow", " pop pop", " } def", "}{", " /xycp {", // xycharpath " currentfont /FontType get 0 eq {", " 0 2 3 index length 1 sub {", " currentpoint 4 index 3 index 2 getinterval false charpath moveto", " 2 copy get 2 index 3 2 roll 1 add get", " pdfTextMat dtransform rmoveto", " } for", " } {", " 0 1 3 index length 1 sub {", " currentpoint 4 index 3 index 1 getinterval false charpath moveto", " 2 copy 2 mul get 2 index 3 2 roll 2 mul 1 add get", " pdfTextMat dtransform rmoveto", " } for", " } ifelse", " pop pop", " } def", "} ifelse", "/Tj {", " fCol", // because stringwidth has to draw Type 3 chars " 0 pdfTextRise pdfTextMat dtransform rmoveto", " currentpoint 4 2 roll", " pdfTextRender 1 and 0 eq {", " 2 copy xyshow2", " } if", " pdfTextRender 3 and dup 1 eq exch 2 eq or {", " 3 index 3 index moveto", " 2 copy", " currentfont /FontType get 3 eq { fCol } { sCol } ifelse", " xycp currentpoint stroke moveto", " } if", " pdfTextRender 4 and 0 ne {", " 4 2 roll moveto xycp", " /pdfTextClipPath [ pdfTextClipPath aload pop", " {/moveto cvx}", " {/lineto cvx}", " {/curveto cvx}", " {/closepath cvx}", " pathforall ] def", " currentpoint newpath moveto", " } {", " pop pop pop pop", " } ifelse", " 0 pdfTextRise neg pdfTextMat dtransform rmoveto", "} def", "/TJm { 0.001 mul pdfFontSize mul pdfHorizScaling mul neg 0", " pdfTextMat dtransform rmoveto } def", "/TJmV { 0.001 mul pdfFontSize mul neg 0 exch", " pdfTextMat dtransform rmoveto } def", "/Tclip { pdfTextClipPath cvx exec clip newpath", " /pdfTextClipPath [] def } def", "~1ns", "% Level 1 image operators", "~1n", "/pdfIm1 {", " /pdfImBuf1 4 index string def", " { currentfile pdfImBuf1 readhexstring pop } image", "} def", "~1s", "/pdfIm1Sep {", " /pdfImBuf1 4 index string def", " /pdfImBuf2 4 index string def", " /pdfImBuf3 4 index string def", " /pdfImBuf4 4 index string def", " { currentfile pdfImBuf1 readhexstring pop }", " { currentfile pdfImBuf2 readhexstring pop }", " { currentfile pdfImBuf3 readhexstring pop }", " { currentfile pdfImBuf4 readhexstring pop }", " true 4 colorimage", "} def", "~1ns", "/pdfImM1 {", " fCol /pdfImBuf1 4 index 7 add 8 idiv string def", " { currentfile pdfImBuf1 readhexstring pop } imagemask", "} def", "/pdfImStr {", " 2 copy exch length lt {", " 2 copy get exch 1 add exch", " } {", " ()", " } ifelse", "} def", "/pdfImM1a {", " { pdfImStr } imagemask", " pop pop", "} def", "~23sn", "% Level 2/3 image operators", "/pdfImBuf 100 string def", "/pdfImStr {", " 2 copy exch length lt {", " 2 copy get exch 1 add exch", " } {", " ()", " } ifelse", "} def", "/skipEOD {", " { currentfile pdfImBuf readline", " not { pop exit } if", " (%-EOD-) eq { exit } if } loop", "} def", "/pdfIm { image skipEOD } def", "~3sn", "/pdfMask {", " /ReusableStreamDecode filter", " skipEOD", " /maskStream exch def", "} def", "/pdfMaskEnd { maskStream closefile } def", "/pdfMaskInit {", " /maskArray exch def", " /maskIdx 0 def", "} def", "/pdfMaskSrc {", " maskIdx maskArray length lt {", " maskArray maskIdx get", " /maskIdx maskIdx 1 add def", " } {", " ()", " } ifelse", "} def", "~23s", "/pdfImSep {", " findcmykcustomcolor exch", " dup /Width get /pdfImBuf1 exch string def", " dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def", " /pdfImDecodeLow exch def", " begin Width Height BitsPerComponent ImageMatrix DataSource end", " /pdfImData exch def", " { pdfImData pdfImBuf1 readstring pop", " 0 1 2 index length 1 sub {", " 1 index exch 2 copy get", " pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi", " 255 exch sub put", " } for }", " 6 5 roll customcolorimage", " skipEOD", "} def", "~23sn", "/pdfImM { fCol imagemask skipEOD } def", "/pr { 2 index 2 index 3 2 roll putinterval 4 add } def", "/pdfImClip {", " gsave", " 0 2 4 index length 1 sub {", " dup 4 index exch 2 copy", " get 5 index div put", " 1 add 3 index exch 2 copy", " get 3 index div put", " } for", " pop pop rectclip", "} def", "/pdfImClipEnd { grestore } def", "~23sn", "% shading operators", "/colordelta {", " false 0 1 3 index length 1 sub {", " dup 4 index exch get 3 index 3 2 roll get sub abs 0.004 gt {", " pop true", " } if", " } for", " exch pop exch pop", "} def", "/funcCol { func n array astore } def", "/funcSH {", " dup 0 eq {", " true", " } {", " dup 6 eq {", " false", " } {", " 4 index 4 index funcCol dup", " 6 index 4 index funcCol dup", " 3 1 roll colordelta 3 1 roll", " 5 index 5 index funcCol dup", " 3 1 roll colordelta 3 1 roll", " 6 index 8 index funcCol dup", " 3 1 roll colordelta 3 1 roll", " colordelta or or or", " } ifelse", " } ifelse", " {", " 1 add", " 4 index 3 index add 0.5 mul exch 4 index 3 index add 0.5 mul exch", " 6 index 6 index 4 index 4 index 4 index funcSH", " 2 index 6 index 6 index 4 index 4 index funcSH", " 6 index 2 index 4 index 6 index 4 index funcSH", " 5 3 roll 3 2 roll funcSH pop pop", " } {", " pop 3 index 2 index add 0.5 mul 3 index 2 index add 0.5 mul", "~23n", " funcCol sc", "~23s", " funcCol aload pop k", "~23sn", " dup 4 index exch mat transform m", " 3 index 3 index mat transform l", " 1 index 3 index mat transform l", " mat transform l pop pop h f*", " } ifelse", "} def", "/axialCol {", " dup 0 lt {", " pop t0", " } {", " dup 1 gt {", " pop t1", " } {", " dt mul t0 add", " } ifelse", " } ifelse", " func n array astore", "} def", "/axialSH {", " dup 2 lt {", " true", " } {", " dup 8 eq {", " false", " } {", " 2 index axialCol 2 index axialCol colordelta", " } ifelse", " } ifelse", " {", " 1 add 3 1 roll 2 copy add 0.5 mul", " dup 4 3 roll exch 4 index axialSH", " exch 3 2 roll axialSH", " } {", " pop 2 copy add 0.5 mul", "~23n", " axialCol sc", "~23s", " axialCol aload pop k", "~23sn", " exch dup dx mul x0 add exch dy mul y0 add", " 3 2 roll dup dx mul x0 add exch dy mul y0 add", " dx abs dy abs ge {", " 2 copy yMin sub dy mul dx div add yMin m", " yMax sub dy mul dx div add yMax l", " 2 copy yMax sub dy mul dx div add yMax l", " yMin sub dy mul dx div add yMin l", " h f*", " } {", " exch 2 copy xMin sub dx mul dy div add xMin exch m", " xMax sub dx mul dy div add xMax exch l", " exch 2 copy xMax sub dx mul dy div add xMax exch l", " xMin sub dx mul dy div add xMin exch l", " h f*", " } ifelse", " } ifelse", "} def", "/radialCol {", " dup t0 lt {", " pop t0", " } {", " dup t1 gt {", " pop t1", " } if", " } ifelse", " func n array astore", "} def", "/radialSH {", " dup 0 eq {", " true", " } {", " dup 8 eq {", " false", " } {", " 2 index dt mul t0 add radialCol", " 2 index dt mul t0 add radialCol colordelta", " } ifelse", " } ifelse", " {", " 1 add 3 1 roll 2 copy add 0.5 mul", " dup 4 3 roll exch 4 index radialSH", " exch 3 2 roll radialSH", " } {", " pop 2 copy add 0.5 mul dt mul t0 add", "~23n", " radialCol sc", "~23s", " radialCol aload pop k", "~23sn", " encl {", " exch dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " 0 360 arc h", " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " 360 0 arcn h f", " } {", " 2 copy", " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " a1 a2 arcn", " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " a2 a1 arcn h", " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " a1 a2 arc", " dup dx mul x0 add exch dup dy mul y0 add exch dr mul r0 add", " a2 a1 arc h f", " } ifelse", " } ifelse", "} def", "~123sn", "end", NULL }; static const char *cmapProlog[] = { "/CIDInit /ProcSet findresource begin", "10 dict begin", " begincmap", " /CMapType 1 def", " /CMapName /Identity-H def", " /CIDSystemInfo 3 dict dup begin", " /Registry (Adobe) def", " /Ordering (Identity) def", " /Supplement 0 def", " end def", " 1 begincodespacerange", " <0000> ", " endcodespacerange", " 0 usefont", " 1 begincidrange", " <0000> 0", " endcidrange", " endcmap", " currentdict CMapName exch /CMap defineresource pop", "end", "10 dict begin", " begincmap", " /CMapType 1 def", " /CMapName /Identity-V def", " /CIDSystemInfo 3 dict dup begin", " /Registry (Adobe) def", " /Ordering (Identity) def", " /Supplement 0 def", " end def", " /WMode 1 def", " 1 begincodespacerange", " <0000> ", " endcodespacerange", " 0 usefont", " 1 begincidrange", " <0000> 0", " endcidrange", " endcmap", " currentdict CMapName exch /CMap defineresource pop", "end", "end", NULL }; //------------------------------------------------------------------------ // Fonts //------------------------------------------------------------------------ struct PSSubstFont { const char *psName; // PostScript name double mWidth; // width of 'm' character }; // NB: must be in same order as base14SubstFonts in GfxFont.cc static PSSubstFont psBase14SubstFonts[14] = { {"Courier", 0.600}, {"Courier-Oblique", 0.600}, {"Courier-Bold", 0.600}, {"Courier-BoldOblique", 0.600}, {"Helvetica", 0.833}, {"Helvetica-Oblique", 0.833}, {"Helvetica-Bold", 0.889}, {"Helvetica-BoldOblique", 0.889}, {"Times-Roman", 0.788}, {"Times-Italic", 0.722}, {"Times-Bold", 0.833}, {"Times-BoldItalic", 0.778}, // the last two are never used for substitution {"Symbol", 0}, {"ZapfDingbats", 0} }; // Mapping from Type 1/1C font file to PS font name. struct PST1FontName { Ref fontFileID; GString *psName; // PostScript font name used for this // embedded font file }; // Info for 8-bit fonts struct PSFont8Info { Ref fontID; int *codeToGID; // code-to-GID mapping for TrueType fonts }; // Encoding info for substitute 16-bit font struct PSFont16Enc { Ref fontID; GString *enc; // NULL means font wasn't correctly substituted }; //------------------------------------------------------------------------ // process colors //------------------------------------------------------------------------ #define psProcessCyan 1 #define psProcessMagenta 2 #define psProcessYellow 4 #define psProcessBlack 8 #define psProcessCMYK 15 //------------------------------------------------------------------------ // PSOutCustomColor //------------------------------------------------------------------------ class PSOutCustomColor { public: PSOutCustomColor(double cA, double mA, double yA, double kA, GString *nameA); ~PSOutCustomColor(); double c, m, y, k; GString *name; PSOutCustomColor *next; }; PSOutCustomColor::PSOutCustomColor(double cA, double mA, double yA, double kA, GString *nameA) { c = cA; m = mA; y = yA; k = kA; name = nameA; next = NULL; } PSOutCustomColor::~PSOutCustomColor() { delete name; } //------------------------------------------------------------------------ struct PSOutImgClipRect { int x0, x1, y0, y1; }; //------------------------------------------------------------------------ struct PSOutPaperSize { PSOutPaperSize(int wA, int hA) { w = wA; h = hA; } int w, h; }; //------------------------------------------------------------------------ // DeviceNRecoder //------------------------------------------------------------------------ class DeviceNRecoder: public FilterStream { public: DeviceNRecoder(Stream *strA, int widthA, int heightA, GfxImageColorMap *colorMapA); virtual ~DeviceNRecoder(); virtual StreamKind getKind() { return strWeird; } virtual void reset(); virtual int getChar() { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } virtual int lookChar() { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } private: GBool fillBuf(); int width, height; GfxImageColorMap *colorMap; Function *func; ImageStream *imgStr; int buf[gfxColorMaxComps]; int pixelIdx; int bufIdx; int bufSize; }; DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA, GfxImageColorMap *colorMapA): FilterStream(strA) { width = widthA; height = heightA; colorMap = colorMapA; imgStr = NULL; pixelIdx = 0; bufIdx = gfxColorMaxComps; bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> getAlt()->getNComps(); func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> getTintTransformFunc(); } DeviceNRecoder::~DeviceNRecoder() { if (imgStr) { delete imgStr; } if (str->isEncoder()) { delete str; } } void DeviceNRecoder::reset() { imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); } GBool DeviceNRecoder::fillBuf() { Guchar pixBuf[gfxColorMaxComps]; GfxColor color; double x[gfxColorMaxComps], y[gfxColorMaxComps]; int i; if (pixelIdx >= width * height) { return gFalse; } imgStr->getPixel(pixBuf); colorMap->getColor(pixBuf, &color); for (i = 0; i < ((GfxDeviceNColorSpace *)colorMap->getColorSpace())->getNComps(); ++i) { x[i] = colToDbl(color.c[i]); } func->transform(x, y); for (i = 0; i < bufSize; ++i) { buf[i] = (int)(y[i] * 255 + 0.5); } bufIdx = 0; ++pixelIdx; return gTrue; } //------------------------------------------------------------------------ // PSOutputDev //------------------------------------------------------------------------ extern "C" { typedef void (*SignalFunc)(int); } static void outputToFile(void *stream, const char *data, int len) { fwrite(data, 1, len, (FILE *)stream); } PSOutputDev::PSOutputDev(char *fileName, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA, PSOutCustomCodeCbk customCodeCbkA, void *customCodeCbkDataA) { FILE *f; PSFileType fileTypeA; underlayCbk = NULL; underlayCbkData = NULL; overlayCbk = NULL; overlayCbkData = NULL; customCodeCbk = customCodeCbkA; customCodeCbkData = customCodeCbkDataA; fontIDs = NULL; fontNames = new GHash(gTrue); t1FontNames = NULL; font8Info = NULL; font16Enc = NULL; imgIDs = NULL; formIDs = NULL; xobjStack = NULL; paperSizes = NULL; embFontList = NULL; customColors = NULL; haveTextClip = gFalse; t3String = NULL; // open file or pipe if (!strcmp(fileName, "-")) { fileTypeA = psStdout; f = stdout; } else if (fileName[0] == '|') { fileTypeA = psPipe; #ifdef HAVE_POPEN #ifndef WIN32 signal(SIGPIPE, (SignalFunc)SIG_IGN); #endif if (!(f = popen(fileName + 1, "w"))) { error(errIO, -1, "Couldn't run print command '{0:s}'", fileName); ok = gFalse; return; } #else error(errIO, -1, "Print commands are not supported ('{0:s}')", fileName); ok = gFalse; return; #endif } else { fileTypeA = psFile; if (!(f = fopen(fileName, "w"))) { error(errIO, -1, "Couldn't open PostScript file '{0:s}'", fileName); ok = gFalse; return; } } init(outputToFile, f, fileTypeA, docA, firstPage, lastPage, modeA, imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); } PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA, PSOutCustomCodeCbk customCodeCbkA, void *customCodeCbkDataA) { underlayCbk = NULL; underlayCbkData = NULL; overlayCbk = NULL; overlayCbkData = NULL; customCodeCbk = customCodeCbkA; customCodeCbkData = customCodeCbkDataA; fontIDs = NULL; fontNames = new GHash(gTrue); t1FontNames = NULL; font8Info = NULL; font16Enc = NULL; imgIDs = NULL; formIDs = NULL; xobjStack = NULL; paperSizes = NULL; embFontList = NULL; customColors = NULL; haveTextClip = gFalse; t3String = NULL; init(outputFuncA, outputStreamA, psGeneric, docA, firstPage, lastPage, modeA, imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); } void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, PSFileType fileTypeA, PDFDoc *docA, int firstPage, int lastPage, PSOutMode modeA, int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA) { Catalog *catalog; Page *page; PDFRectangle *box; PSOutPaperSize *size; GList *names; int pg, w, h, i; // initialize ok = gTrue; outputFunc = outputFuncA; outputStream = outputStreamA; fileType = fileTypeA; doc = docA; xref = doc->getXRef(); catalog = doc->getCatalog(); level = globalParams->getPSLevel(); mode = modeA; paperWidth = globalParams->getPSPaperWidth(); paperHeight = globalParams->getPSPaperHeight(); imgLLX = imgLLXA; imgLLY = imgLLYA; imgURX = imgURXA; imgURY = imgURYA; if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) { globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); } if (paperWidth < 0 || paperHeight < 0) { paperMatch = gTrue; paperSizes = new GList(); paperWidth = paperHeight = 1; // in case the document has zero pages for (pg = (firstPage >= 1) ? firstPage : 1; pg <= lastPage && pg <= catalog->getNumPages(); ++pg) { page = catalog->getPage(pg); w = (int)ceil(page->getMediaWidth()); h = (int)ceil(page->getMediaHeight()); for (i = 0; i < paperSizes->getLength(); ++i) { size = (PSOutPaperSize *)paperSizes->get(i); if (size->w == w && size->h == h) { break; } } if (i == paperSizes->getLength()) { paperSizes->append(new PSOutPaperSize(w, h)); } if (w > paperWidth) { paperWidth = w; } if (h > paperHeight) { paperHeight = h; } } // NB: img{LLX,LLY,URX,URY} will be set by startPage() } else { paperMatch = gFalse; } preload = globalParams->getPSPreload(); manualCtrl = manualCtrlA; if (mode == psModeForm) { lastPage = firstPage; } processColors = 0; inType3Char = gFalse; #if OPI_SUPPORT // initialize OPI nesting levels opi13Nest = 0; opi20Nest = 0; #endif tx0 = ty0 = -1; xScale0 = yScale0 = 0; rotate0 = -1; clipLLX0 = clipLLY0 = 0; clipURX0 = clipURY0 = -1; // initialize fontIDs and fontNames lists fontIDSize = 64; fontIDLen = 0; fontIDs = (Ref *)gmallocn(fontIDSize, sizeof(Ref)); for (i = 0; i < 14; ++i) { fontNames->add(new GString(psBase14SubstFonts[i].psName), 1); } names = globalParams->getPSResidentFonts(); for (i = 0; i < names->getLength(); ++i) { fontNames->add((GString *)names->get(i), 1); } delete names; t1FontNameSize = 64; t1FontNameLen = 0; t1FontNames = (PST1FontName *)gmallocn(t1FontNameSize, sizeof(PST1FontName)); font8InfoLen = 0; font8InfoSize = 0; font16EncLen = 0; font16EncSize = 0; imgIDLen = 0; imgIDSize = 0; formIDLen = 0; formIDSize = 0; xobjStack = new GList(); numSaves = 0; numTilingPatterns = 0; nextFunc = 0; // initialize embedded font resource comment list embFontList = new GString(); if (!manualCtrl) { // this check is needed in case the document has zero pages if (firstPage > 0 && firstPage <= catalog->getNumPages()) { writeHeader(firstPage, lastPage, catalog->getPage(firstPage)->getMediaBox(), catalog->getPage(firstPage)->getCropBox(), catalog->getPage(firstPage)->getRotate()); } else { box = new PDFRectangle(0, 0, 1, 1); writeHeader(firstPage, lastPage, box, box, 0); delete box; } if (mode != psModeForm) { writePS("%%BeginProlog\n"); } writeXpdfProcset(); if (mode != psModeForm) { writePS("%%EndProlog\n"); writePS("%%BeginSetup\n"); } writeDocSetup(catalog, firstPage, lastPage); if (mode != psModeForm) { writePS("%%EndSetup\n"); } } // initialize sequential page number seqPage = 1; } PSOutputDev::~PSOutputDev() { PSOutCustomColor *cc; int i; if (ok) { if (!manualCtrl) { writePS("%%Trailer\n"); writeTrailer(); if (mode != psModeForm) { writePS("%%EOF\n"); } } if (fileType == psFile) { #ifdef MACOS ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle); #endif fclose((FILE *)outputStream); } #ifdef HAVE_POPEN else if (fileType == psPipe) { pclose((FILE *)outputStream); #ifndef WIN32 signal(SIGPIPE, (SignalFunc)SIG_DFL); #endif } #endif } if (paperSizes) { deleteGList(paperSizes, PSOutPaperSize); } if (embFontList) { delete embFontList; } if (fontIDs) { gfree(fontIDs); } delete fontNames; if (t1FontNames) { for (i = 0; i < t1FontNameLen; ++i) { delete t1FontNames[i].psName; } gfree(t1FontNames); } if (font8Info) { for (i = 0; i < font8InfoLen; ++i) { gfree(font8Info[i].codeToGID); } gfree(font8Info); } if (font16Enc) { for (i = 0; i < font16EncLen; ++i) { if (font16Enc[i].enc) { delete font16Enc[i].enc; } } gfree(font16Enc); } gfree(imgIDs); gfree(formIDs); if (xobjStack) { delete xobjStack; } while (customColors) { cc = customColors; customColors = cc->next; delete cc; } } void PSOutputDev::writeHeader(int firstPage, int lastPage, PDFRectangle *mediaBox, PDFRectangle *cropBox, int pageRotate) { Object info, obj1; PSOutPaperSize *size; double x1, y1, x2, y2; int i; switch (mode) { case psModePS: writePS("%!PS-Adobe-3.0\n"); break; case psModeEPS: writePS("%!PS-Adobe-3.0 EPSF-3.0\n"); break; case psModeForm: writePS("%!PS-Adobe-3.0 Resource-Form\n"); break; } writePSFmt("%XpdfVersion: {0:s}\n", xpdfVersion); xref->getDocInfo(&info); if (info.isDict() && info.dictLookup("Creator", &obj1)->isString()) { writePS("%%Creator: "); writePSTextLine(obj1.getString()); } obj1.free(); if (info.isDict() && info.dictLookup("Title", &obj1)->isString()) { writePS("%%Title: "); writePSTextLine(obj1.getString()); } obj1.free(); info.free(); writePSFmt("%%LanguageLevel: {0:d}\n", (level == psLevel1 || level == psLevel1Sep) ? 1 : (level == psLevel2 || level == psLevel2Sep) ? 2 : 3); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { writePS("%%DocumentProcessColors: (atend)\n"); writePS("%%DocumentCustomColors: (atend)\n"); } writePS("%%DocumentSuppliedResources: (atend)\n"); switch (mode) { case psModePS: if (paperMatch) { for (i = 0; i < paperSizes->getLength(); ++i) { size = (PSOutPaperSize *)paperSizes->get(i); writePSFmt("%%{0:s} {1:d}x{2:d} {1:d} {2:d} 0 () ()\n", i==0 ? "DocumentMedia:" : "+", size->w, size->h); } } else { writePSFmt("%%DocumentMedia: plain {0:d} {1:d} 0 () ()\n", paperWidth, paperHeight); } writePSFmt("%%BoundingBox: 0 0 {0:d} {1:d}\n", paperWidth, paperHeight); writePSFmt("%%Pages: {0:d}\n", lastPage - firstPage + 1); writePS("%%EndComments\n"); if (!paperMatch) { writePS("%%BeginDefaults\n"); writePS("%%PageMedia: plain\n"); writePS("%%EndDefaults\n"); } break; case psModeEPS: epsX1 = cropBox->x1; epsY1 = cropBox->y1; epsX2 = cropBox->x2; epsY2 = cropBox->y2; if (pageRotate == 0 || pageRotate == 180) { x1 = epsX1; y1 = epsY1; x2 = epsX2; y2 = epsY2; } else { // pageRotate == 90 || pageRotate == 270 x1 = 0; y1 = 0; x2 = epsY2 - epsY1; y2 = epsX2 - epsX1; } writePSFmt("%%BoundingBox: {0:d} {1:d} {2:d} {3:d}\n", (int)floor(x1), (int)floor(y1), (int)ceil(x2), (int)ceil(y2)); if (floor(x1) != ceil(x1) || floor(y1) != ceil(y1) || floor(x2) != ceil(x2) || floor(y2) != ceil(y2)) { writePSFmt("%%HiResBoundingBox: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n", x1, y1, x2, y2); } writePS("%%EndComments\n"); break; case psModeForm: writePS("%%EndComments\n"); writePS("32 dict dup begin\n"); writePSFmt("/BBox [{0:d} {1:d} {2:d} {3:d}] def\n", (int)floor(mediaBox->x1), (int)floor(mediaBox->y1), (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2)); writePS("/FormType 1 def\n"); writePS("/Matrix [1 0 0 1 0 0] def\n"); break; } } void PSOutputDev::writeXpdfProcset() { GBool lev1, lev2, lev3, sep, nonSep; const char **p; const char *q; writePSFmt("%%BeginResource: procset xpdf {0:s} 0\n", xpdfVersion); writePSFmt("%%Copyright: {0:s}\n", xpdfCopyright); lev1 = lev2 = lev3 = sep = nonSep = gTrue; for (p = prolog; *p; ++p) { if ((*p)[0] == '~') { lev1 = lev2 = lev3 = sep = nonSep = gFalse; for (q = *p + 1; *q; ++q) { switch (*q) { case '1': lev1 = gTrue; break; case '2': lev2 = gTrue; break; case '3': lev3 = gTrue; break; case 's': sep = gTrue; break; case 'n': nonSep = gTrue; break; } } } else if ((level == psLevel1 && lev1 && nonSep) || (level == psLevel1Sep && lev1 && sep) || (level == psLevel2 && lev2 && nonSep) || (level == psLevel2Sep && lev2 && sep) || (level == psLevel3 && lev3 && nonSep) || (level == psLevel3Sep && lev3 && sep)) { writePSFmt("{0:s}\n", *p); } } writePS("%%EndResource\n"); if (level >= psLevel3) { for (p = cmapProlog; *p; ++p) { writePSFmt("{0:s}\n", *p); } } } void PSOutputDev::writeDocSetup(Catalog *catalog, int firstPage, int lastPage) { Page *page; Dict *resDict; Annots *annots; Object *acroForm; Object obj1, obj2, obj3; GString *s; int pg, i; if (mode == psModeForm) { // swap the form and xpdf dicts writePS("xpdf end begin dup begin\n"); } else { writePS("xpdf begin\n"); } for (pg = firstPage; pg <= lastPage; ++pg) { page = catalog->getPage(pg); if ((resDict = page->getResourceDict())) { setupResources(resDict); } annots = new Annots(doc, page->getAnnots(&obj1)); obj1.free(); for (i = 0; i < annots->getNumAnnots(); ++i) { if (annots->getAnnot(i)->getAppearance(&obj1)->isStream()) { obj1.streamGetDict()->lookup("Resources", &obj2); if (obj2.isDict()) { setupResources(obj2.getDict()); } obj2.free(); } obj1.free(); } delete annots; } if ((acroForm = catalog->getAcroForm()) && acroForm->isDict()) { if (acroForm->dictLookup("DR", &obj1)->isDict()) { setupResources(obj1.getDict()); } obj1.free(); if (acroForm->dictLookup("Fields", &obj1)->isArray()) { for (i = 0; i < obj1.arrayGetLength(); ++i) { if (obj1.arrayGet(i, &obj2)->isDict()) { if (obj2.dictLookup("DR", &obj3)->isDict()) { setupResources(obj3.getDict()); } obj3.free(); } obj2.free(); } } obj1.free(); } if (mode != psModeForm) { if (mode != psModeEPS && !manualCtrl) { writePSFmt("{0:s} pdfSetup\n", globalParams->getPSDuplex() ? "true" : "false"); if (!paperMatch) { writePSFmt("{0:d} {1:d} pdfSetupPaper\n", paperWidth, paperHeight); } } #if OPI_SUPPORT if (globalParams->getPSOPI()) { writePS("/opiMatrix matrix currentmatrix def\n"); } #endif } if (customCodeCbk) { if ((s = (*customCodeCbk)(this, psOutCustomDocSetup, 0, customCodeCbkData))) { writePS(s->getCString()); delete s; } } } void PSOutputDev::writePageTrailer() { if (mode != psModeForm) { writePS("pdfEndPage\n"); } } void PSOutputDev::writeTrailer() { PSOutCustomColor *cc; if (mode == psModeForm) { writePS("/Foo exch /Form defineresource pop\n"); } else { writePS("end\n"); writePS("%%DocumentSuppliedResources:\n"); writePS(embFontList->getCString()); if (level == psLevel1Sep || level == psLevel2Sep || level == psLevel3Sep) { writePS("%%DocumentProcessColors:"); if (processColors & psProcessCyan) { writePS(" Cyan"); } if (processColors & psProcessMagenta) { writePS(" Magenta"); } if (processColors & psProcessYellow) { writePS(" Yellow"); } if (processColors & psProcessBlack) { writePS(" Black"); } writePS("\n"); writePS("%%DocumentCustomColors:"); for (cc = customColors; cc; cc = cc->next) { writePS(" "); writePSString(cc->name); } writePS("\n"); writePS("%%CMYKCustomColor:\n"); for (cc = customColors; cc; cc = cc->next) { writePSFmt("%%+ {0:.4g} {1:.4g} {2:.4g} {3:.4g} ", cc->c, cc->m, cc->y, cc->k); writePSString(cc->name); writePS("\n"); } } } } void PSOutputDev::setupResources(Dict *resDict) { Object xObjDict, xObjRef, xObj, patDict, patRef, pat, resObj; Ref ref0, ref1; GBool skip; int i, j; setupFonts(resDict); setupImages(resDict); setupForms(resDict); //----- recursively scan XObjects resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { // avoid infinite recursion on XObjects skip = gFalse; if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) { ref0 = xObjRef.getRef(); for (j = 0; j < xobjStack->getLength(); ++j) { ref1 = *(Ref *)xobjStack->get(j); if (ref1.num == ref0.num && ref1.gen == ref0.gen) { skip = gTrue; break; } } if (!skip) { xobjStack->append(&ref0); } } if (!skip) { // process the XObject's resource dictionary xObjDict.dictGetVal(i, &xObj); if (xObj.isStream()) { xObj.streamGetDict()->lookup("Resources", &resObj); if (resObj.isDict()) { setupResources(resObj.getDict()); } resObj.free(); } xObj.free(); } if (xObjRef.isRef() && !skip) { xobjStack->del(xobjStack->getLength() - 1); } xObjRef.free(); } } xObjDict.free(); //----- recursively scan Patterns resDict->lookup("Pattern", &patDict); if (patDict.isDict()) { inType3Char = gTrue; for (i = 0; i < patDict.dictGetLength(); ++i) { // avoid infinite recursion on Patterns skip = gFalse; if ((patDict.dictGetValNF(i, &patRef)->isRef())) { ref0 = patRef.getRef(); for (j = 0; j < xobjStack->getLength(); ++j) { ref1 = *(Ref *)xobjStack->get(j); if (ref1.num == ref0.num && ref1.gen == ref0.gen) { skip = gTrue; break; } } if (!skip) { xobjStack->append(&ref0); } } if (!skip) { // process the Pattern's resource dictionary patDict.dictGetVal(i, &pat); if (pat.isStream()) { pat.streamGetDict()->lookup("Resources", &resObj); if (resObj.isDict()) { setupResources(resObj.getDict()); } resObj.free(); } pat.free(); } if (patRef.isRef() && !skip) { xobjStack->del(xobjStack->getLength() - 1); } patRef.free(); } inType3Char = gFalse; } patDict.free(); } void PSOutputDev::setupFonts(Dict *resDict) { Object obj1, obj2; Ref r; GfxFontDict *gfxFontDict; GfxFont *font; int i; gfxFontDict = NULL; resDict->lookupNF("Font", &obj1); if (obj1.isRef()) { obj1.fetch(xref, &obj2); if (obj2.isDict()) { r = obj1.getRef(); gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict()); } obj2.free(); } else if (obj1.isDict()) { gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict()); } if (gfxFontDict) { for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { if ((font = gfxFontDict->getFont(i))) { setupFont(font, resDict); } } delete gfxFontDict; } obj1.free(); } void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) { GfxFontLoc *fontLoc; GString *psName; GBool subst; char buf[16]; UnicodeMap *uMap; char *charName; double xs, ys; int code; double w1, w2; int i, j; // check if font is already set up for (i = 0; i < fontIDLen; ++i) { if (fontIDs[i].num == font->getID()->num && fontIDs[i].gen == font->getID()->gen) { return; } } // add entry to fontIDs list if (fontIDLen >= fontIDSize) { fontIDSize += 64; fontIDs = (Ref *)greallocn(fontIDs, fontIDSize, sizeof(Ref)); } fontIDs[fontIDLen++] = *font->getID(); psName = NULL; xs = ys = 1; subst = gFalse; if (font->getType() == fontType3) { psName = GString::format("T3_{0:d}_{1:d}", font->getID()->num, font->getID()->gen); setupType3Font(font, psName, parentResDict); } else { fontLoc = font->locateFont(xref, gTrue); switch (fontLoc->locType) { case gfxFontLocEmbedded: switch (fontLoc->fontType) { case fontType1: // this assumes that the PS font name matches the PDF font name psName = font->getEmbeddedFontName()->copy(); setupEmbeddedType1Font(&fontLoc->embFontID, psName); break; case fontType1C: psName = makePSFontName(font, &fontLoc->embFontID); setupEmbeddedType1CFont(font, &fontLoc->embFontID, psName); break; case fontType1COT: psName = makePSFontName(font, &fontLoc->embFontID); setupEmbeddedOpenTypeT1CFont(font, &fontLoc->embFontID, psName); break; case fontTrueType: case fontTrueTypeOT: psName = makePSFontName(font, font->getID()); setupEmbeddedTrueTypeFont(font, &fontLoc->embFontID, psName); break; case fontCIDType0C: psName = makePSFontName(font, &fontLoc->embFontID); setupEmbeddedCIDType0Font(font, &fontLoc->embFontID, psName); break; case fontCIDType2: case fontCIDType2OT: psName = makePSFontName(font, font->getID()); //~ should check to see if font actually uses vertical mode setupEmbeddedCIDTrueTypeFont(font, &fontLoc->embFontID, psName, gTrue); break; case fontCIDType0COT: psName = makePSFontName(font, &fontLoc->embFontID); setupEmbeddedOpenTypeCFFFont(font, &fontLoc->embFontID, psName); break; default: break; } break; case gfxFontLocExternal: //~ add cases for external 16-bit fonts switch (fontLoc->fontType) { case fontType1: if (font->getName()) { // this assumes that the PS font name matches the PDF font name psName = font->getName()->copy(); } else { //~ this won't work -- the PS font name won't match psName = makePSFontName(font, font->getID()); } setupExternalType1Font(fontLoc->path, psName); break; case fontTrueType: case fontTrueTypeOT: psName = makePSFontName(font, font->getID()); setupExternalTrueTypeFont(font, fontLoc->path, psName); break; case fontCIDType2: case fontCIDType2OT: psName = makePSFontName(font, font->getID()); //~ should check to see if font actually uses vertical mode setupExternalCIDTrueTypeFont(font, fontLoc->path, psName, gTrue); break; default: break; } break; case gfxFontLocResident: psName = fontLoc->path->copy(); break; } if (!psName) { if (font->isCIDFont()) { error(errSyntaxError, -1, "Couldn't find a font to substitute for '{0:s}' ('{1:s}' character collection)", font->getName() ? font->getName()->getCString() : "(unnamed)", ((GfxCIDFont *)font)->getCollection() ? ((GfxCIDFont *)font)->getCollection()->getCString() : "(unknown)"); if (font16EncLen >= font16EncSize) { font16EncSize += 16; font16Enc = (PSFont16Enc *)greallocn(font16Enc, font16EncSize, sizeof(PSFont16Enc)); } font16Enc[font16EncLen].fontID = *font->getID(); font16Enc[font16EncLen].enc = NULL; ++font16EncLen; } else { error(errSyntaxError, -1, "Couldn't find a font to substitute for '{0:s}'", font->getName() ? font->getName()->getCString() : "(unnamed)"); } delete fontLoc; return; } // scale substituted 8-bit fonts if (fontLoc->locType == gfxFontLocResident && fontLoc->substIdx >= 0) { subst = gTrue; for (code = 0; code < 256; ++code) { if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) && charName[0] == 'm' && charName[1] == '\0') { break; } } if (code < 256) { w1 = ((Gfx8BitFont *)font)->getWidth(code); } else { w1 = 0; } w2 = psBase14SubstFonts[fontLoc->substIdx].mWidth; xs = w1 / w2; if (xs < 0.1) { xs = 1; } } // handle encodings for substituted CID fonts if (fontLoc->locType == gfxFontLocResident && fontLoc->fontType >= fontCIDType0) { subst = gTrue; if (font16EncLen >= font16EncSize) { font16EncSize += 16; font16Enc = (PSFont16Enc *)greallocn(font16Enc, font16EncSize, sizeof(PSFont16Enc)); } font16Enc[font16EncLen].fontID = *font->getID(); if ((uMap = globalParams->getUnicodeMap(fontLoc->encoding))) { font16Enc[font16EncLen].enc = fontLoc->encoding->copy(); uMap->decRefCnt(); } else { error(errSyntaxError, -1, "Couldn't find Unicode map for 16-bit font encoding '{0:t}'", fontLoc->encoding); font16Enc[font16EncLen].enc = NULL; } ++font16EncLen; } delete fontLoc; } // generate PostScript code to set up the font if (font->isCIDFont()) { if (level == psLevel3 || level == psLevel3Sep) { writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16L3\n", font->getID()->num, font->getID()->gen, psName, font->getWMode()); } else { writePSFmt("/F{0:d}_{1:d} /{2:t} {3:d} pdfMakeFont16\n", font->getID()->num, font->getID()->gen, psName, font->getWMode()); } } else { writePSFmt("/F{0:d}_{1:d} /{2:t} {3:.6g} {4:.6g}\n", font->getID()->num, font->getID()->gen, psName, xs, ys); for (i = 0; i < 256; i += 8) { writePS((char *)((i == 0) ? "[ " : " ")); for (j = 0; j < 8; ++j) { if (font->getType() == fontTrueType && !subst && !((Gfx8BitFont *)font)->getHasEncoding()) { sprintf(buf, "c%02x", i+j); charName = buf; } else { charName = ((Gfx8BitFont *)font)->getCharName(i+j); } writePS("/"); writePSName(charName ? charName : (char *)".notdef"); // the empty name is legal in PDF and PostScript, but PostScript // uses a double-slash (//...) for "immediately evaluated names", // so we need to add a space character here if (charName && !charName[0]) { writePS(" "); } } writePS((i == 256-8) ? (char *)"]\n" : (char *)"\n"); } writePS("pdfMakeFont\n"); } delete psName; } void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) { static char hexChar[17] = "0123456789abcdef"; Object refObj, strObj, obj1, obj2, obj3; Dict *dict; int length1, length2, length3; int c; int start[4]; GBool binMode; int i; // check if font is already embedded if (fontNames->lookupInt(psName)) { return; } fontNames->add(psName->copy(), 1); // get the font stream and info refObj.initRef(id->num, id->gen); refObj.fetch(xref, &strObj); refObj.free(); if (!strObj.isStream()) { error(errSyntaxError, -1, "Embedded font file object is not a stream"); goto err1; } if (!(dict = strObj.streamGetDict())) { error(errSyntaxError, -1, "Embedded font stream is missing its dictionary"); goto err1; } dict->lookup("Length1", &obj1); dict->lookup("Length2", &obj2); dict->lookup("Length3", &obj3); if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) { error(errSyntaxError, -1, "Missing length fields in embedded font stream dictionary"); obj1.free(); obj2.free(); obj3.free(); goto err1; } length1 = obj1.getInt(); length2 = obj2.getInt(); length3 = obj3.getInt(); obj1.free(); obj2.free(); obj3.free(); // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // copy ASCII portion of font strObj.streamReset(); for (i = 0; i < length1 && (c = strObj.streamGetChar()) != EOF; ++i) { writePSChar(c); } // figure out if encrypted portion is binary or ASCII binMode = gFalse; for (i = 0; i < 4; ++i) { start[i] = strObj.streamGetChar(); if (start[i] == EOF) { error(errSyntaxError, -1, "Unexpected end of file in embedded font stream"); goto err1; } if (!((start[i] >= '0' && start[i] <= '9') || (start[i] >= 'A' && start[i] <= 'F') || (start[i] >= 'a' && start[i] <= 'f'))) binMode = gTrue; } // convert binary data to ASCII if (binMode) { for (i = 0; i < 4; ++i) { writePSChar(hexChar[(start[i] >> 4) & 0x0f]); writePSChar(hexChar[start[i] & 0x0f]); } #if 0 // this causes trouble for various PostScript printers // if Length2 is incorrect (too small), font data gets chopped, so // we take a few extra characters from the trailer just in case length2 += length3 >= 8 ? 8 : length3; #endif while (i < length2) { if ((c = strObj.streamGetChar()) == EOF) { break; } writePSChar(hexChar[(c >> 4) & 0x0f]); writePSChar(hexChar[c & 0x0f]); if (++i % 32 == 0) { writePSChar('\n'); } } if (i % 32 > 0) { writePSChar('\n'); } // already in ASCII format -- just copy it } else { for (i = 0; i < 4; ++i) { writePSChar(start[i]); } for (i = 4; i < length2; ++i) { if ((c = strObj.streamGetChar()) == EOF) { break; } writePSChar(c); } } // write padding and "cleartomark" for (i = 0; i < 8; ++i) { writePS("00000000000000000000000000000000" "00000000000000000000000000000000\n"); } writePS("cleartomark\n"); // ending comment writePS("%%EndResource\n"); err1: strObj.streamClose(); strObj.free(); } //~ This doesn't handle .pfb files or binary eexec data (which only //~ happens in pfb files?). void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) { FILE *fontFile; int c; // check if font is already embedded if (fontNames->lookupInt(psName)) { return; } fontNames->add(psName->copy(), 1); // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // copy the font file if (!(fontFile = fopen(fileName->getCString(), "rb"))) { error(errIO, -1, "Couldn't open external font file"); return; } while ((c = fgetc(fontFile)) != EOF) { writePSChar(c); } fclose(fontFile); // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; FoFiType1C *ffT1C; int i; // check if font is already embedded for (i = 0; i < t1FontNameLen; ++i) { if (t1FontNames[i].fontFileID.num == id->num && t1FontNames[i].fontFileID.gen == id->gen) { psName->clear(); psName->insert(0, t1FontNames[i].psName); return; } } if (t1FontNameLen == t1FontNameSize) { t1FontNameSize *= 2; t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, sizeof(PST1FontName)); } t1FontNames[t1FontNameLen].fontFileID = *id; t1FontNames[t1FontNameLen].psName = psName->copy(); ++t1FontNameLen; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 1 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { ffT1C->convertToType1(psName->getCString(), NULL, gTrue, outputFunc, outputStream); delete ffT1C; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedOpenTypeT1CFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; FoFiTrueType *ffTT; int i; // check if font is already embedded for (i = 0; i < t1FontNameLen; ++i) { if (t1FontNames[i].fontFileID.num == id->num && t1FontNames[i].fontFileID.gen == id->gen) { psName->clear(); psName->insert(0, t1FontNames[i].psName); return; } } if (t1FontNameLen == t1FontNameSize) { t1FontNameSize *= 2; t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, sizeof(PST1FontName)); } t1FontNames[t1FontNameLen].fontFileID = *id; t1FontNames[t1FontNameLen].psName = psName->copy(); ++t1FontNameLen; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 1 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { if (ffTT->isOpenTypeCFF()) { ffTT->convertToType1(psName->getCString(), NULL, gTrue, outputFunc, outputStream); } delete ffTT; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; FoFiTrueType *ffTT; int *codeToGID; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 42 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); ffTT->convertToType42(psName->getCString(), ((Gfx8BitFont *)font)->getHasEncoding() ? ((Gfx8BitFont *)font)->getEncoding() : (char **)NULL, codeToGID, outputFunc, outputStream); if (codeToGID) { if (font8InfoLen >= font8InfoSize) { font8InfoSize += 16; font8Info = (PSFont8Info *)greallocn(font8Info, font8InfoSize, sizeof(PSFont8Info)); } font8Info[font8InfoLen].fontID = *font->getID(); font8Info[font8InfoLen].codeToGID = codeToGID; ++font8InfoLen; } delete ffTT; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *fileName, GString *psName) { FoFiTrueType *ffTT; int *codeToGID; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 42 font if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); ffTT->convertToType42(psName->getCString(), ((Gfx8BitFont *)font)->getHasEncoding() ? ((Gfx8BitFont *)font)->getEncoding() : (char **)NULL, codeToGID, outputFunc, outputStream); if (codeToGID) { if (font8InfoLen >= font8InfoSize) { font8InfoSize += 16; font8Info = (PSFont8Info *)greallocn(font8Info, font8InfoSize, sizeof(PSFont8Info)); } font8Info[font8InfoLen].fontID = *font->getID(); font8Info[font8InfoLen].codeToGID = codeToGID; ++font8InfoLen; } delete ffTT; } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; FoFiType1C *ffT1C; int i; // check if font is already embedded for (i = 0; i < t1FontNameLen; ++i) { if (t1FontNames[i].fontFileID.num == id->num && t1FontNames[i].fontFileID.gen == id->gen) { psName->clear(); psName->insert(0, t1FontNames[i].psName); return; } } if (t1FontNameLen == t1FontNameSize) { t1FontNameSize *= 2; t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, sizeof(PST1FontName)); } t1FontNames[t1FontNameLen].fontFileID = *id; t1FontNames[t1FontNameLen].psName = psName->copy(); ++t1FontNameLen; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 0 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font ffT1C->convertToCIDType0(psName->getCString(), NULL, 0, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffT1C->convertToType0(psName->getCString(), NULL, 0, outputFunc, outputStream); } delete ffT1C; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName, GBool needVerticalMetrics) { char *fontBuf; int fontLen; FoFiTrueType *ffTT; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 0 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font ffTT->convertToCIDType2(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), needVerticalMetrics, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffTT->convertToType0(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), needVerticalMetrics, outputFunc, outputStream); } delete ffTT; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupExternalCIDTrueTypeFont(GfxFont *font, GString *fileName, GString *psName, GBool needVerticalMetrics) { FoFiTrueType *ffTT; int *codeToGID; int codeToGIDLen; CharCodeToUnicode *ctu; Unicode uBuf[8]; int cmap, code; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 0 font //~ this should use fontNum to load the correct font if ((ffTT = FoFiTrueType::load(fileName->getCString()))) { // check for embedding permission if (ffTT->getEmbeddingRights() >= 1) { // create a CID-to-GID mapping, via Unicode if ((ctu = ((GfxCIDFont *)font)->getToUnicode())) { // look for a Unicode cmap for (cmap = 0; cmap < ffTT->getNumCmaps(); ++cmap) { if ((ffTT->getCmapPlatform(cmap) == 3 && ffTT->getCmapEncoding(cmap) == 1) || ffTT->getCmapPlatform(cmap) == 0) { break; } } if (cmap < ffTT->getNumCmaps()) { // map CID -> Unicode -> GID codeToGIDLen = ctu->getLength(); codeToGID = (int *)gmallocn(codeToGIDLen, sizeof(int)); for (code = 0; code < codeToGIDLen; ++code) { if (ctu->mapToUnicode(code, uBuf, 8) > 0) { codeToGID[code] = ffTT->mapCodeToGID(cmap, uBuf[0]); } else { codeToGID[code] = 0; } } if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font ffTT->convertToCIDType2(psName->getCString(), codeToGID, codeToGIDLen, needVerticalMetrics, outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffTT->convertToType0(psName->getCString(), codeToGID, codeToGIDLen, needVerticalMetrics, outputFunc, outputStream); } gfree(codeToGID); } ctu->decRefCnt(); } else { error(errSyntaxError, -1, "Couldn't find a mapping to Unicode for font '{0:s}'", font->getName() ? font->getName()->getCString() : "(unnamed)"); } } else { error(errSyntaxError, -1, "TrueType font '%s' does not allow embedding", font->getName() ? font->getName()->getCString() : "(unnamed)"); } delete ffTT; } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupEmbeddedOpenTypeCFFFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; FoFiTrueType *ffTT; int i; // check if font is already embedded for (i = 0; i < t1FontNameLen; ++i) { if (t1FontNames[i].fontFileID.num == id->num && t1FontNames[i].fontFileID.gen == id->gen) { psName->clear(); psName->insert(0, t1FontNames[i].psName); return; } } if (t1FontNameLen == t1FontNameSize) { t1FontNameSize *= 2; t1FontNames = (PST1FontName *)greallocn(t1FontNames, t1FontNameSize, sizeof(PST1FontName)); } t1FontNames[t1FontNameLen].fontFileID = *id; t1FontNames[t1FontNameLen].psName = psName->copy(); ++t1FontNameLen; // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // convert it to a Type 0 font if ((fontBuf = font->readEmbFontFile(xref, &fontLen))) { if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { if (ffTT->isOpenTypeCFF()) { if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font ffTT->convertToCIDType0(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), outputFunc, outputStream); } else { // otherwise: use a non-CID composite font ffTT->convertToType0(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), outputFunc, outputStream); } } delete ffTT; } gfree(fontBuf); } // ending comment writePS("%%EndResource\n"); } void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict) { Dict *resDict; Dict *charProcs; Object charProc; Gfx *gfx; PDFRectangle box; double *m; GString *buf; int i; // set up resources used by font if ((resDict = ((Gfx8BitFont *)font)->getResources())) { inType3Char = gTrue; setupResources(resDict); inType3Char = gFalse; } else { resDict = parentResDict; } // beginning comment writePSFmt("%%BeginResource: font {0:t}\n", psName); embFontList->append("%%+ font "); embFontList->append(psName->getCString()); embFontList->append("\n"); // font dictionary writePS("8 dict begin\n"); writePS("/FontType 3 def\n"); m = font->getFontMatrix(); writePSFmt("/FontMatrix [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n", m[0], m[1], m[2], m[3], m[4], m[5]); m = font->getFontBBox(); writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n", m[0], m[1], m[2], m[3]); writePS("/Encoding 256 array def\n"); writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); writePS("/BuildGlyph {\n"); writePS(" exch /CharProcs get exch\n"); writePS(" 2 copy known not { pop /.notdef } if\n"); writePS(" get exec\n"); writePS("} bind def\n"); writePS("/BuildChar {\n"); writePS(" 1 index /Encoding get exch get\n"); writePS(" 1 index /BuildGlyph get exec\n"); writePS("} bind def\n"); if ((charProcs = ((Gfx8BitFont *)font)->getCharProcs())) { writePSFmt("/CharProcs {0:d} dict def\n", charProcs->getLength()); writePS("CharProcs begin\n"); box.x1 = m[0]; box.y1 = m[1]; box.x2 = m[2]; box.y2 = m[3]; gfx = new Gfx(doc, this, resDict, &box, NULL); inType3Char = gTrue; for (i = 0; i < charProcs->getLength(); ++i) { t3FillColorOnly = gFalse; t3Cacheable = gFalse; t3NeedsRestore = gFalse; writePS("/"); writePSName(charProcs->getKey(i)); writePS(" {\n"); gfx->display(charProcs->getVal(i, &charProc)); charProc.free(); if (t3String) { if (t3Cacheable) { buf = GString::format("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} setcachedevice\n", t3WX, t3WY, t3LLX, t3LLY, t3URX, t3URY); } else { buf = GString::format("{0:.6g} {1:.6g} setcharwidth\n", t3WX, t3WY); } (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, t3String->getCString(), t3String->getLength()); delete t3String; t3String = NULL; } if (t3NeedsRestore) { (*outputFunc)(outputStream, "Q\n", 2); } writePS("} def\n"); } inType3Char = gFalse; delete gfx; writePS("end\n"); } writePS("currentdict end\n"); writePSFmt("/{0:t} exch definefont pop\n", psName); // ending comment writePS("%%EndResource\n"); } // Make a unique PS font name, based on the names given in the PDF // font object, and an object ID (font file object for GString *PSOutputDev::makePSFontName(GfxFont *font, Ref *id) { GString *psName, *s; if ((s = font->getEmbeddedFontName())) { psName = filterPSName(s); if (!fontNames->lookupInt(psName)) { fontNames->add(psName->copy(), 1); return psName; } delete psName; } if ((s = font->getName())) { psName = filterPSName(s); if (!fontNames->lookupInt(psName)) { fontNames->add(psName->copy(), 1); return psName; } delete psName; } psName = GString::format("FF{0:d}_{1:d}", id->num, id->gen); if ((s = font->getEmbeddedFontName())) { s = filterPSName(s); psName->append('_')->append(s); delete s; } else if ((s = font->getName())) { s = filterPSName(s); psName->append('_')->append(s); delete s; } fontNames->add(psName->copy(), 1); return psName; } void PSOutputDev::setupImages(Dict *resDict) { Object xObjDict, xObj, xObjRef, subtypeObj, maskObj, maskRef; Ref imgID; int i, j; if (!(mode == psModeForm || inType3Char || preload)) { return; } resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { xObjDict.dictGetValNF(i, &xObjRef); xObjDict.dictGetVal(i, &xObj); if (xObj.isStream()) { xObj.streamGetDict()->lookup("Subtype", &subtypeObj); if (subtypeObj.isName("Image")) { if (xObjRef.isRef()) { imgID = xObjRef.getRef(); for (j = 0; j < imgIDLen; ++j) { if (imgIDs[j].num == imgID.num && imgIDs[j].gen == imgID.gen) { break; } } if (j == imgIDLen) { if (imgIDLen >= imgIDSize) { if (imgIDSize == 0) { imgIDSize = 64; } else { imgIDSize *= 2; } imgIDs = (Ref *)greallocn(imgIDs, imgIDSize, sizeof(Ref)); } imgIDs[imgIDLen++] = imgID; setupImage(imgID, xObj.getStream(), gFalse); if (level >= psLevel3 && xObj.streamGetDict()->lookup("Mask", &maskObj)->isStream()) { setupImage(imgID, maskObj.getStream(), gTrue); } maskObj.free(); } } else { error(errSyntaxError, -1, "Image in resource dict is not an indirect reference"); } } subtypeObj.free(); } xObj.free(); xObjRef.free(); } } xObjDict.free(); } void PSOutputDev::setupImage(Ref id, Stream *str, GBool mask) { GBool useRLE, useCompressed, useASCIIHex; GString *s; int c; int size, line, col, i; // filters //~ this does not correctly handle the DeviceN color space //~ -- need to use DeviceNRecoder if (level < psLevel2) { useRLE = gFalse; useCompressed = gFalse; useASCIIHex = gTrue; } else { if (globalParams->getPSUncompressPreloadedImages()) { useRLE = gFalse; useCompressed = gFalse; } else { s = str->getPSFilter(level < psLevel3 ? 2 : 3, ""); if (s) { useRLE = gFalse; useCompressed = gTrue; delete s; } else { useRLE = gTrue; useCompressed = gFalse; } } useASCIIHex = globalParams->getPSASCIIHex(); } if (useCompressed) { str = str->getUndecodedStream(); } if (useRLE) { str = new RunLengthEncoder(str); } if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); } // compute image data size str->reset(); col = size = 0; do { do { c = str->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { ++col; } else { ++col; for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } ++col; } } if (col > 225) { ++size; col = 0; } } while (c != (useASCIIHex ? '>' : '~') && c != EOF); // add one entry for the final line of data; add another entry // because the RunLengthDecode filter may read past the end ++size; if (useRLE) { ++size; } writePSFmt("{0:d} array dup /{1:s}Data_{2:d}_{3:d} exch def\n", size, mask ? "Mask" : "Im", id.num, id.gen); str->close(); // write the data into the array str->reset(); line = col = 0; writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~")); do { do { c = str->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { writePSChar(c); ++col; } else { writePSChar(c); ++col; for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } writePSChar(c); ++col; } } // each line is: "dup nnnnn <~...data...~> put" // so max data length = 255 - 20 = 235 // chunks are 1 or 4 bytes each, so we have to stop at 232 // but make it 225 just to be safe if (col > 225) { writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); ++line; writePSFmt((char *)(useASCIIHex ? "dup {0:d} <" : "dup {0:d} <~"), line); col = 0; } } while (c != (useASCIIHex ? '>' : '~') && c != EOF); writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); if (useRLE) { ++line; writePSFmt("{0:d} <> put\n", line); } else { writePS("pop\n"); } str->close(); delete str; } void PSOutputDev::setupForms(Dict *resDict) { Object xObjDict, xObj, xObjRef, subtypeObj; int i; if (!preload) { return; } resDict->lookup("XObject", &xObjDict); if (xObjDict.isDict()) { for (i = 0; i < xObjDict.dictGetLength(); ++i) { xObjDict.dictGetValNF(i, &xObjRef); xObjDict.dictGetVal(i, &xObj); if (xObj.isStream()) { xObj.streamGetDict()->lookup("Subtype", &subtypeObj); if (subtypeObj.isName("Form")) { if (xObjRef.isRef()) { setupForm(xObjRef.getRef(), &xObj); } else { error(errSyntaxError, -1, "Form in resource dict is not an indirect reference"); } } subtypeObj.free(); } xObj.free(); xObjRef.free(); } } xObjDict.free(); } void PSOutputDev::setupForm(Ref id, Object *strObj) { Dict *dict, *resDict; Object matrixObj, bboxObj, resObj, obj1; double m[6], bbox[4]; PDFRectangle box; Gfx *gfx; int i; // check if form is already defined for (i = 0; i < formIDLen; ++i) { if (formIDs[i].num == id.num && formIDs[i].gen == id.gen) { return; } } // add entry to formIDs list if (formIDLen >= formIDSize) { if (formIDSize == 0) { formIDSize = 64; } else { formIDSize *= 2; } formIDs = (Ref *)greallocn(formIDs, formIDSize, sizeof(Ref)); } formIDs[formIDLen++] = id; dict = strObj->streamGetDict(); // get bounding box dict->lookup("BBox", &bboxObj); if (!bboxObj.isArray()) { bboxObj.free(); error(errSyntaxError, -1, "Bad form bounding box"); return; } for (i = 0; i < 4; ++i) { bboxObj.arrayGet(i, &obj1); bbox[i] = obj1.getNum(); obj1.free(); } bboxObj.free(); // get matrix dict->lookup("Matrix", &matrixObj); if (matrixObj.isArray()) { for (i = 0; i < 6; ++i) { matrixObj.arrayGet(i, &obj1); m[i] = obj1.getNum(); obj1.free(); } } else { m[0] = 1; m[1] = 0; m[2] = 0; m[3] = 1; m[4] = 0; m[5] = 0; } matrixObj.free(); // get resources dict->lookup("Resources", &resObj); resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL; writePSFmt("/f_{0:d}_{1:d} {{\n", id.num, id.gen); writePS("q\n"); writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] cm\n", m[0], m[1], m[2], m[3], m[4], m[5]); box.x1 = bbox[0]; box.y1 = bbox[1]; box.x2 = bbox[2]; box.y2 = bbox[3]; gfx = new Gfx(doc, this, resDict, &box, &box); gfx->display(strObj); delete gfx; writePS("Q\n"); writePS("} def\n"); resObj.free(); } GBool PSOutputDev::checkPageSlice(Page *page, double hDPI, double vDPI, int rotateA, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { PreScanOutputDev *scan; GBool rasterize; #if HAVE_SPLASH GBool mono; double dpi; SplashOutputDev *splashOut; SplashColor paperColor; PDFRectangle box; GfxState *state; SplashBitmap *bitmap; Stream *str0, *str; Object obj; Guchar *p; Guchar col[4]; double hDPI2, vDPI2; double m0, m1, m2, m3, m4, m5; int nStripes, stripeH, stripeY; int c, w, h, x, y, comp, i; #endif if (globalParams->getPSAlwaysRasterize()) { rasterize = gTrue; } else { scan = new PreScanOutputDev(); page->displaySlice(scan, 72, 72, rotateA, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData); rasterize = scan->usesTransparency() || scan->usesPatternImageMask(); delete scan; } if (!rasterize) { return gTrue; } #if HAVE_SPLASH // get the rasterization parameters dpi = globalParams->getPSRasterResolution(); mono = globalParams->getPSRasterMono(); // start the PS page page->makeBox(dpi, dpi, rotateA, useMediaBox, gFalse, sliceX, sliceY, sliceW, sliceH, &box, &crop); rotateA += page->getRotate(); if (rotateA >= 360) { rotateA -= 360; } else if (rotateA < 0) { rotateA += 360; } state = new GfxState(dpi, dpi, &box, rotateA, gFalse); startPage(page->getNum(), state); delete state; // set up the SplashOutputDev if (mono || level == psLevel1) { paperColor[0] = 0xff; splashOut = new SplashOutputDev(splashModeMono8, 1, gFalse, paperColor, gFalse, globalParams->getAntialiasPrinting()); #if SPLASH_CMYK } else if (level == psLevel1Sep) { paperColor[0] = paperColor[1] = paperColor[2] = paperColor[3] = 0; splashOut = new SplashOutputDev(splashModeCMYK8, 1, gFalse, paperColor, gFalse, globalParams->getAntialiasPrinting()); #endif } else { paperColor[0] = paperColor[1] = paperColor[2] = 0xff; splashOut = new SplashOutputDev(splashModeRGB8, 1, gFalse, paperColor, gFalse, globalParams->getAntialiasPrinting()); } splashOut->startDoc(xref); // break the page into stripes hDPI2 = xScale * dpi; vDPI2 = yScale * dpi; if (sliceW < 0 || sliceH < 0) { if (useMediaBox) { box = *page->getMediaBox(); } else { box = *page->getCropBox(); } sliceX = sliceY = 0; sliceW = (int)((box.x2 - box.x1) * hDPI2 / 72.0); sliceH = (int)((box.y2 - box.y1) * vDPI2 / 72.0); } nStripes = (int)ceil((double)(sliceW * sliceH) / (double)rasterizationSliceSize); stripeH = (sliceH + nStripes - 1) / nStripes; // render the stripes for (stripeY = sliceY; stripeY < sliceH; stripeY += stripeH) { // rasterize a stripe page->makeBox(hDPI2, vDPI2, 0, useMediaBox, gFalse, sliceX, stripeY, sliceW, stripeH, &box, &crop); m0 = box.x2 - box.x1; m1 = 0; m2 = 0; m3 = box.y2 - box.y1; m4 = box.x1; m5 = box.y1; page->displaySlice(splashOut, hDPI2, vDPI2, (360 - page->getRotate()) % 360, useMediaBox, crop, sliceX, stripeY, sliceW, stripeH, printing, abortCheckCbk, abortCheckCbkData); // draw the rasterized image bitmap = splashOut->getBitmap(); w = bitmap->getWidth(); h = bitmap->getHeight(); writePS("gsave\n"); writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", m0, m1, m2, m3, m4, m5); switch (level) { case psLevel1: writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", w, h, w, -h, h); p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); i = 0; for (y = 0; y < h; ++y) { for (x = 0; x < w; ++x) { writePSFmt("{0:02x}", *p++); if (++i == 32) { writePSChar('\n'); i = 0; } } } if (i != 0) { writePSChar('\n'); } break; case psLevel1Sep: writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", w, h, w, -h, h); p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); i = 0; col[0] = col[1] = col[2] = col[3] = 0; for (y = 0; y < h; ++y) { for (comp = 0; comp < 4; ++comp) { for (x = 0; x < w; ++x) { writePSFmt("{0:02x}", p[4*x + comp]); col[comp] |= p[4*x + comp]; if (++i == 32) { writePSChar('\n'); i = 0; } } } p -= bitmap->getRowSize(); } if (i != 0) { writePSChar('\n'); } if (col[0]) { processColors |= psProcessCyan; } if (col[1]) { processColors |= psProcessMagenta; } if (col[2]) { processColors |= psProcessYellow; } if (col[3]) { processColors |= psProcessBlack; } break; case psLevel2: case psLevel2Sep: case psLevel3: case psLevel3Sep: if (mono) { writePS("/DeviceGray setcolorspace\n"); } else { writePS("/DeviceRGB setcolorspace\n"); } writePS("<<\n /ImageType 1\n"); writePSFmt(" /Width {0:d}\n", bitmap->getWidth()); writePSFmt(" /Height {0:d}\n", bitmap->getHeight()); writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", w, -h, h); writePS(" /BitsPerComponent 8\n"); if (mono) { writePS(" /Decode [0 1]\n"); } else { writePS(" /Decode [0 1 0 1 0 1]\n"); } writePS(" /DataSource currentfile\n"); if (globalParams->getPSASCIIHex()) { writePS(" /ASCIIHexDecode filter\n"); } else { writePS(" /ASCII85Decode filter\n"); } writePS(" /RunLengthDecode filter\n"); writePS(">>\n"); writePS("image\n"); obj.initNull(); p = bitmap->getDataPtr() + (h - 1) * bitmap->getRowSize(); str0 = new MemStream((char *)p, 0, w * h * (mono ? 1 : 3), &obj); str = new RunLengthEncoder(str0); if (globalParams->getPSASCIIHex()) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); } str->reset(); while ((c = str->getChar()) != EOF) { writePSChar(c); } str->close(); delete str; delete str0; writePSChar('\n'); processColors |= mono ? psProcessBlack : psProcessCMYK; break; } writePS("grestore\n"); } delete splashOut; // finish the PS page endPage(); return gFalse; #else // HAVE_SPLASH error(errSyntaxWarning, -1, "PDF page uses transparency and PSOutputDev was built without" " the Splash rasterizer - output may not be correct"); return gTrue; #endif // HAVE_SPLASH } void PSOutputDev::startPage(int pageNum, GfxState *state) { Page *page; int x1, y1, x2, y2, width, height, t; int imgWidth, imgHeight, imgWidth2, imgHeight2; GBool landscape; GString *s; if (mode == psModePS) { writePSFmt("%%Page: {0:d} {1:d}\n", pageNum, seqPage); if (paperMatch) { page = doc->getCatalog()->getPage(pageNum); imgLLX = imgLLY = 0; imgURX = (int)ceil(page->getMediaWidth()); imgURY = (int)ceil(page->getMediaHeight()); if (state->getRotate() == 90 || state->getRotate() == 270) { t = imgURX; imgURX = imgURY; imgURY = t; } writePSFmt("%%PageMedia: {0:d}x{1:d}\n", imgURX, imgURY); writePSFmt("%%PageBoundingBox: 0 0 {0:d} {1:d}\n", imgURX, imgURY); } writePS("%%BeginPageSetup\n"); } // underlays if (underlayCbk) { (*underlayCbk)(this, underlayCbkData); } if (overlayCbk) { saveState(NULL); } switch (mode) { case psModePS: // rotate, translate, and scale page imgWidth = imgURX - imgLLX; imgHeight = imgURY - imgLLY; x1 = (int)floor(state->getX1()); y1 = (int)floor(state->getY1()); x2 = (int)ceil(state->getX2()); y2 = (int)ceil(state->getY2()); width = x2 - x1; height = y2 - y1; tx = ty = 0; // rotation and portrait/landscape mode if (paperMatch) { rotate = (360 - state->getRotate()) % 360; landscape = gFalse; } else if (rotate0 >= 0) { rotate = (360 - rotate0) % 360; landscape = gFalse; } else { rotate = (360 - state->getRotate()) % 360; if (rotate == 0 || rotate == 180) { if ((width < height && imgWidth > imgHeight && height > imgHeight) || (width > height && imgWidth < imgHeight && width > imgWidth)) { rotate += 90; landscape = gTrue; } else { landscape = gFalse; } } else { // rotate == 90 || rotate == 270 if ((height < width && imgWidth > imgHeight && width > imgHeight) || (height > width && imgWidth < imgHeight && height > imgWidth)) { rotate = 270 - rotate; landscape = gTrue; } else { landscape = gFalse; } } } writePSFmt("%%PageOrientation: {0:s}\n", landscape ? "Landscape" : "Portrait"); if (paperMatch) { writePSFmt("{0:d} {1:d} pdfSetupPaper\n", imgURX, imgURY); } writePS("pdfStartPage\n"); if (rotate == 0) { imgWidth2 = imgWidth; imgHeight2 = imgHeight; } else if (rotate == 90) { writePS("90 rotate\n"); ty = -imgWidth; imgWidth2 = imgHeight; imgHeight2 = imgWidth; } else if (rotate == 180) { writePS("180 rotate\n"); imgWidth2 = imgWidth; imgHeight2 = imgHeight; tx = -imgWidth; ty = -imgHeight; } else { // rotate == 270 writePS("270 rotate\n"); tx = -imgHeight; imgWidth2 = imgHeight; imgHeight2 = imgWidth; } // shrink or expand if (xScale0 > 0 && yScale0 > 0) { xScale = xScale0; yScale = yScale0; } else if ((globalParams->getPSShrinkLarger() && (width > imgWidth2 || height > imgHeight2)) || (globalParams->getPSExpandSmaller() && (width < imgWidth2 && height < imgHeight2))) { xScale = (double)imgWidth2 / (double)width; yScale = (double)imgHeight2 / (double)height; if (yScale < xScale) { xScale = yScale; } else { yScale = xScale; } } else { xScale = yScale = 1; } // deal with odd bounding boxes or clipping if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { tx -= xScale * clipLLX0; ty -= yScale * clipLLY0; } else { tx -= xScale * x1; ty -= yScale * y1; } // center if (tx0 >= 0 && ty0 >= 0) { tx += (rotate == 0 || rotate == 180) ? tx0 : ty0; ty += (rotate == 0 || rotate == 180) ? ty0 : -tx0; } else if (globalParams->getPSCenter()) { if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { tx += (imgWidth2 - xScale * (clipURX0 - clipLLX0)) / 2; ty += (imgHeight2 - yScale * (clipURY0 - clipLLY0)) / 2; } else { tx += (imgWidth2 - xScale * width) / 2; ty += (imgHeight2 - yScale * height) / 2; } } tx += (rotate == 0 || rotate == 180) ? imgLLX : imgLLY; ty += (rotate == 0 || rotate == 180) ? imgLLY : -imgLLX; if (tx != 0 || ty != 0) { writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty); } if (xScale != 1 || yScale != 1) { writePSFmt("{0:.4f} {1:.4f} scale\n", xScale, yScale); } if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re W\n", clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); } else { writePSFmt("{0:d} {1:d} {2:d} {3:d} re W\n", x1, y1, x2 - x1, y2 - y1); } ++seqPage; break; case psModeEPS: writePS("pdfStartPage\n"); tx = ty = 0; rotate = (360 - state->getRotate()) % 360; if (rotate == 0) { } else if (rotate == 90) { writePS("90 rotate\n"); tx = -epsX1; ty = -epsY2; } else if (rotate == 180) { writePS("180 rotate\n"); tx = -(epsX1 + epsX2); ty = -(epsY1 + epsY2); } else { // rotate == 270 writePS("270 rotate\n"); tx = -epsX2; ty = -epsY1; } if (tx != 0 || ty != 0) { writePSFmt("{0:.6g} {1:.6g} translate\n", tx, ty); } xScale = yScale = 1; break; case psModeForm: writePS("/PaintProc {\n"); writePS("begin xpdf begin\n"); writePS("pdfStartPage\n"); tx = ty = 0; xScale = yScale = 1; rotate = 0; break; } if (customCodeCbk) { if ((s = (*customCodeCbk)(this, psOutCustomPageSetup, pageNum, customCodeCbkData))) { writePS(s->getCString()); delete s; } } if (mode == psModePS) { writePS("%%EndPageSetup\n"); } } void PSOutputDev::endPage() { if (overlayCbk) { restoreState(NULL); (*overlayCbk)(this, overlayCbkData); } if (mode == psModeForm) { writePS("pdfEndPage\n"); writePS("end end\n"); writePS("} def\n"); writePS("end end\n"); } else { if (!manualCtrl) { writePS("showpage\n"); } writePS("%%PageTrailer\n"); writePageTrailer(); } } void PSOutputDev::saveState(GfxState *state) { writePS("q\n"); ++numSaves; } void PSOutputDev::restoreState(GfxState *state) { writePS("Q\n"); --numSaves; } void PSOutputDev::updateCTM(GfxState *state, double m11, double m12, double m21, double m22, double m31, double m32) { writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] cm\n", m11, m12, m21, m22, m31, m32); } void PSOutputDev::updateLineDash(GfxState *state) { double *dash; double start; int length, i; state->getLineDash(&dash, &length, &start); writePS("["); for (i = 0; i < length; ++i) { writePSFmt("{0:.6g}{1:w}", dash[i] < 0 ? 0 : dash[i], (i == length-1) ? 0 : 1); } writePSFmt("] {0:.6g} d\n", start); } void PSOutputDev::updateFlatness(GfxState *state) { writePSFmt("{0:d} i\n", state->getFlatness()); } void PSOutputDev::updateLineJoin(GfxState *state) { writePSFmt("{0:d} j\n", state->getLineJoin()); } void PSOutputDev::updateLineCap(GfxState *state) { writePSFmt("{0:d} J\n", state->getLineCap()); } void PSOutputDev::updateMiterLimit(GfxState *state) { writePSFmt("{0:.4g} M\n", state->getMiterLimit()); } void PSOutputDev::updateLineWidth(GfxState *state) { writePSFmt("{0:.6g} w\n", state->getLineWidth()); } void PSOutputDev::updateFillColorSpace(GfxState *state) { switch (level) { case psLevel1: case psLevel1Sep: break; case psLevel2: case psLevel3: if (state->getFillColorSpace()->getMode() != csPattern) { dumpColorSpaceL2(state->getFillColorSpace(), gTrue, gFalse, gFalse); writePS(" cs\n"); } break; case psLevel2Sep: case psLevel3Sep: break; } } void PSOutputDev::updateStrokeColorSpace(GfxState *state) { switch (level) { case psLevel1: case psLevel1Sep: break; case psLevel2: case psLevel3: if (state->getStrokeColorSpace()->getMode() != csPattern) { dumpColorSpaceL2(state->getStrokeColorSpace(), gTrue, gFalse, gFalse); writePS(" CS\n"); } break; case psLevel2Sep: case psLevel3Sep: break; } } void PSOutputDev::updateFillColor(GfxState *state) { GfxColor color; GfxColor *colorPtr; GfxGray gray; GfxCMYK cmyk; GfxSeparationColorSpace *sepCS; double c, m, y, k; int i; switch (level) { case psLevel1: state->getFillGray(&gray); writePSFmt("{0:.4g} g\n", colToDbl(gray)); break; case psLevel1Sep: state->getFillCMYK(&cmyk); c = colToDbl(cmyk.c); m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k); addProcessColor(c, m, y, k); break; case psLevel2: case psLevel3: if (state->getFillColorSpace()->getMode() != csPattern) { colorPtr = state->getFillColor(); writePS("["); for (i = 0; i < state->getFillColorSpace()->getNComps(); ++i) { if (i > 0) { writePS(" "); } writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i])); } writePS("] sc\n"); } break; case psLevel2Sep: case psLevel3Sep: if (state->getFillColorSpace()->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)state->getFillColorSpace(); color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) ck\n", colToDbl(state->getFillColor()->c[0]), colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()); addCustomColor(sepCS); } else { state->getFillCMYK(&cmyk); c = colToDbl(cmyk.c); m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} k\n", c, m, y, k); addProcessColor(c, m, y, k); } break; } t3Cacheable = gFalse; } void PSOutputDev::updateStrokeColor(GfxState *state) { GfxColor color; GfxColor *colorPtr; GfxGray gray; GfxCMYK cmyk; GfxSeparationColorSpace *sepCS; double c, m, y, k; int i; switch (level) { case psLevel1: state->getStrokeGray(&gray); writePSFmt("{0:.4g} G\n", colToDbl(gray)); break; case psLevel1Sep: state->getStrokeCMYK(&cmyk); c = colToDbl(cmyk.c); m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k); addProcessColor(c, m, y, k); break; case psLevel2: case psLevel3: if (state->getStrokeColorSpace()->getMode() != csPattern) { colorPtr = state->getStrokeColor(); writePS("["); for (i = 0; i < state->getStrokeColorSpace()->getNComps(); ++i) { if (i > 0) { writePS(" "); } writePSFmt("{0:.4g}", colToDbl(colorPtr->c[i])); } writePS("] SC\n"); } break; case psLevel2Sep: case psLevel3Sep: if (state->getStrokeColorSpace()->getMode() == csSeparation) { sepCS = (GfxSeparationColorSpace *)state->getStrokeColorSpace(); color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} ({5:t}) CK\n", colToDbl(state->getStrokeColor()->c[0]), colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()); addCustomColor(sepCS); } else { state->getStrokeCMYK(&cmyk); c = colToDbl(cmyk.c); m = colToDbl(cmyk.m); y = colToDbl(cmyk.y); k = colToDbl(cmyk.k); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} K\n", c, m, y, k); addProcessColor(c, m, y, k); } break; } t3Cacheable = gFalse; } void PSOutputDev::addProcessColor(double c, double m, double y, double k) { if (c > 0) { processColors |= psProcessCyan; } if (m > 0) { processColors |= psProcessMagenta; } if (y > 0) { processColors |= psProcessYellow; } if (k > 0) { processColors |= psProcessBlack; } } void PSOutputDev::addCustomColor(GfxSeparationColorSpace *sepCS) { PSOutCustomColor *cc; GfxColor color; GfxCMYK cmyk; for (cc = customColors; cc; cc = cc->next) { if (!cc->name->cmp(sepCS->getName())) { return; } } color.c[0] = gfxColorComp1; sepCS->getCMYK(&color, &cmyk); cc = new PSOutCustomColor(colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()->copy()); cc->next = customColors; customColors = cc; } void PSOutputDev::updateFillOverprint(GfxState *state) { if (level >= psLevel2) { writePSFmt("{0:s} op\n", state->getFillOverprint() ? "true" : "false"); } } void PSOutputDev::updateStrokeOverprint(GfxState *state) { if (level >= psLevel2) { writePSFmt("{0:s} OP\n", state->getStrokeOverprint() ? "true" : "false"); } } void PSOutputDev::updateTransfer(GfxState *state) { Function **funcs; int i; funcs = state->getTransfer(); if (funcs[0] && funcs[1] && funcs[2] && funcs[3]) { if (level >= psLevel2) { for (i = 0; i < 4; ++i) { cvtFunction(funcs[i]); } writePS("setcolortransfer\n"); } else { cvtFunction(funcs[3]); writePS("settransfer\n"); } } else if (funcs[0]) { cvtFunction(funcs[0]); writePS("settransfer\n"); } else { writePS("{} settransfer\n"); } } void PSOutputDev::updateFont(GfxState *state) { if (state->getFont()) { writePSFmt("/F{0:d}_{1:d} {2:.6g} Tf\n", state->getFont()->getID()->num, state->getFont()->getID()->gen, fabs(state->getFontSize()) < 0.0001 ? 0.0001 : state->getFontSize()); } } void PSOutputDev::updateTextMat(GfxState *state) { double *mat; mat = state->getTextMat(); if (fabs(mat[0] * mat[3] - mat[1] * mat[2]) < 0.00001) { // avoid a singular (or close-to-singular) matrix writePSFmt("[0.00001 0 0 0.00001 {0:.6g} {1:.6g}] Tm\n", mat[4], mat[5]); } else { writePSFmt("[{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] Tm\n", mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); } } void PSOutputDev::updateCharSpace(GfxState *state) { writePSFmt("{0:.6g} Tc\n", state->getCharSpace()); } void PSOutputDev::updateRender(GfxState *state) { int rm; rm = state->getRender(); writePSFmt("{0:d} Tr\n", rm); rm &= 3; if (rm != 0 && rm != 3) { t3Cacheable = gFalse; } } void PSOutputDev::updateRise(GfxState *state) { writePSFmt("{0:.6g} Ts\n", state->getRise()); } void PSOutputDev::updateWordSpace(GfxState *state) { writePSFmt("{0:.6g} Tw\n", state->getWordSpace()); } void PSOutputDev::updateHorizScaling(GfxState *state) { double h; h = state->getHorizScaling(); if (fabs(h) < 0.01) { h = 0.01; } writePSFmt("{0:.6g} Tz\n", h); } void PSOutputDev::updateTextPos(GfxState *state) { writePSFmt("{0:.6g} {1:.6g} Td\n", state->getLineX(), state->getLineY()); } void PSOutputDev::updateTextShift(GfxState *state, double shift) { if (state->getFont()->getWMode()) { writePSFmt("{0:.6g} TJmV\n", shift); } else { writePSFmt("{0:.6g} TJm\n", shift); } } void PSOutputDev::saveTextPos(GfxState *state) { writePS("currentpoint\n"); } void PSOutputDev::restoreTextPos(GfxState *state) { writePS("m\n"); } void PSOutputDev::stroke(GfxState *state) { doPath(state->getPath()); if (inType3Char && t3FillColorOnly) { // if we're constructing a cacheable Type 3 glyph, we need to do // everything in the fill color writePS("Sf\n"); } else { writePS("S\n"); } } void PSOutputDev::fill(GfxState *state) { doPath(state->getPath()); writePS("f\n"); } void PSOutputDev::eoFill(GfxState *state) { doPath(state->getPath()); writePS("f*\n"); } void PSOutputDev::tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) { PDFRectangle box; Gfx *gfx2; // define a Type 3 font writePS("8 dict begin\n"); writePS("/FontType 3 def\n"); writePS("/FontMatrix [1 0 0 1 0 0] def\n"); writePSFmt("/FontBBox [{0:.6g} {1:.6g} {2:.6g} {3:.6g}] def\n", bbox[0], bbox[1], bbox[2], bbox[3]); writePS("/Encoding 256 array def\n"); writePS(" 0 1 255 { Encoding exch /.notdef put } for\n"); writePS(" Encoding 120 /x put\n"); writePS("/BuildGlyph {\n"); writePS(" exch /CharProcs get exch\n"); writePS(" 2 copy known not { pop /.notdef } if\n"); writePS(" get exec\n"); writePS("} bind def\n"); writePS("/BuildChar {\n"); writePS(" 1 index /Encoding get exch get\n"); writePS(" 1 index /BuildGlyph get exec\n"); writePS("} bind def\n"); writePS("/CharProcs 1 dict def\n"); writePS("CharProcs begin\n"); box.x1 = bbox[0]; box.y1 = bbox[1]; box.x2 = bbox[2]; box.y2 = bbox[3]; gfx2 = new Gfx(doc, this, resDict, &box, NULL); writePS("/x {\n"); if (paintType == 2) { writePSFmt("{0:.6g} 0 {1:.6g} {2:.6g} {3:.6g} {4:.6g} setcachedevice\n", xStep, bbox[0], bbox[1], bbox[2], bbox[3]); t3FillColorOnly = gTrue; } else { if (x1 - 1 <= x0) { writePS("1 0 setcharwidth\n"); } else { writePSFmt("{0:.6g} 0 setcharwidth\n", xStep); } t3FillColorOnly = gFalse; } inType3Char = gTrue; ++numTilingPatterns; gfx2->display(str); --numTilingPatterns; inType3Char = gFalse; writePS("} def\n"); delete gfx2; writePS("end\n"); writePS("currentdict end\n"); writePSFmt("/xpdfTile{0:d} exch definefont pop\n", numTilingPatterns); // draw the tiles writePSFmt("/xpdfTile{0:d} findfont setfont\n", numTilingPatterns); writePS("fCol\n"); writePSFmt("gsave [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] concat\n", mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); writePSFmt("{0:d} 1 {1:d} {{ {2:.6g} exch {3:.6g} mul m {4:d} 1 {5:d} {{ pop (x) show }} for }} for\n", y0, y1 - 1, x0 * xStep, yStep, x0, x1 - 1); writePS("grestore\n"); } GBool PSOutputDev::functionShadedFill(GfxState *state, GfxFunctionShading *shading) { double x0, y0, x1, y1; double *mat; int i; if (level == psLevel2Sep || level == psLevel3Sep) { if (shading->getColorSpace()->getMode() != csDeviceCMYK) { return gFalse; } processColors |= psProcessCMYK; } shading->getDomain(&x0, &y0, &x1, &y1); mat = shading->getMatrix(); writePSFmt("/mat [{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g}] def\n", mat[0], mat[1], mat[2], mat[3], mat[4], mat[5]); writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); if (shading->getNFuncs() == 1) { writePS("/func "); cvtFunction(shading->getFunc(0)); writePS("def\n"); } else { writePS("/func {\n"); for (i = 0; i < shading->getNFuncs(); ++i) { if (i < shading->getNFuncs() - 1) { writePS("2 copy\n"); } cvtFunction(shading->getFunc(i)); writePS("exec\n"); if (i < shading->getNFuncs() - 1) { writePS("3 1 roll\n"); } } writePS("} def\n"); } writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} 0 funcSH\n", x0, y0, x1, y1); return gTrue; } GBool PSOutputDev::axialShadedFill(GfxState *state, GfxAxialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, x1, y1, dx, dy, mul; double tMin, tMax, t, t0, t1; int i; if (level == psLevel2Sep || level == psLevel3Sep) { if (shading->getColorSpace()->getMode() != csDeviceCMYK) { return gFalse; } processColors |= psProcessCMYK; } // get the clip region bbox state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); // compute min and max t values, based on the four corners of the // clip region bbox shading->getCoords(&x0, &y0, &x1, &y1); dx = x1 - x0; dy = y1 - y0; if (fabs(dx) < 0.01 && fabs(dy) < 0.01) { return gTrue; } else { mul = 1 / (dx * dx + dy * dy); tMin = tMax = ((xMin - x0) * dx + (yMin - y0) * dy) * mul; t = ((xMin - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMin - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } t = ((xMax - x0) * dx + (yMax - y0) * dy) * mul; if (t < tMin) { tMin = t; } else if (t > tMax) { tMax = t; } if (tMin < 0 && !shading->getExtend0()) { tMin = 0; } if (tMax > 1 && !shading->getExtend1()) { tMax = 1; } } // get the function domain t0 = shading->getDomain0(); t1 = shading->getDomain1(); // generate the PS code writePSFmt("/t0 {0:.6g} def\n", t0); writePSFmt("/t1 {0:.6g} def\n", t1); writePSFmt("/dt {0:.6g} def\n", t1 - t0); writePSFmt("/x0 {0:.6g} def\n", x0); writePSFmt("/y0 {0:.6g} def\n", y0); writePSFmt("/dx {0:.6g} def\n", x1 - x0); writePSFmt("/x1 {0:.6g} def\n", x1); writePSFmt("/y1 {0:.6g} def\n", y1); writePSFmt("/dy {0:.6g} def\n", y1 - y0); writePSFmt("/xMin {0:.6g} def\n", xMin); writePSFmt("/yMin {0:.6g} def\n", yMin); writePSFmt("/xMax {0:.6g} def\n", xMax); writePSFmt("/yMax {0:.6g} def\n", yMax); writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); if (shading->getNFuncs() == 1) { writePS("/func "); cvtFunction(shading->getFunc(0)); writePS("def\n"); } else { writePS("/func {\n"); for (i = 0; i < shading->getNFuncs(); ++i) { if (i < shading->getNFuncs() - 1) { writePS("dup\n"); } cvtFunction(shading->getFunc(i)); writePS("exec\n"); if (i < shading->getNFuncs() - 1) { writePS("exch\n"); } } writePS("} def\n"); } writePSFmt("{0:.6g} {1:.6g} 0 axialSH\n", tMin, tMax); return gTrue; } GBool PSOutputDev::radialShadedFill(GfxState *state, GfxRadialShading *shading) { double xMin, yMin, xMax, yMax; double x0, y0, r0, x1, y1, r1, t0, t1; double xa, ya, ra; double sz, sMin, sMax, h, ta; double sLeft, sRight, sTop, sBottom, sZero, sDiag; GBool haveSLeft, haveSRight, haveSTop, haveSBottom, haveSZero; GBool haveSMin, haveSMax; double theta, alpha, a1, a2; GBool enclosed; int i; if (level == psLevel2Sep || level == psLevel3Sep) { if (shading->getColorSpace()->getMode() != csDeviceCMYK) { return gFalse; } processColors |= psProcessCMYK; } // get the shading info shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1); t0 = shading->getDomain0(); t1 = shading->getDomain1(); // Compute the point at which r(s) = 0; check for the enclosed // circles case; and compute the angles for the tangent lines. h = sqrt((x1 - x0) * (x1 - x0) + (y1 - y0) * (y1 - y0)); if (h == 0) { enclosed = gTrue; theta = 0; // make gcc happy sz = 0; // make gcc happy } else if (r1 - r0 == 0) { enclosed = gFalse; theta = 0; sz = 0; // make gcc happy } else if (fabs(r1 - r0) >= h) { enclosed = gTrue; theta = 0; // make gcc happy sz = 0; // make gcc happy } else { enclosed = gFalse; sz = -r0 / (r1 - r0); theta = asin((r1 - r0) / h); } if (enclosed) { a1 = 0; a2 = 360; } else { alpha = atan2(y1 - y0, x1 - x0); a1 = (180 / M_PI) * (alpha + theta) + 90; a2 = (180 / M_PI) * (alpha - theta) - 90; while (a2 < a1) { a2 += 360; } } // compute the (possibly extended) s range state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax); if (enclosed) { sMin = 0; sMax = 1; } else { // solve x(sLeft) + r(sLeft) = xMin if ((haveSLeft = fabs((x1 + r1) - (x0 + r0)) > 0.000001)) { sLeft = (xMin - (x0 + r0)) / ((x1 + r1) - (x0 + r0)); } else { sLeft = 0; // make gcc happy } // solve x(sRight) - r(sRight) = xMax if ((haveSRight = fabs((x1 - r1) - (x0 - r0)) > 0.000001)) { sRight = (xMax - (x0 - r0)) / ((x1 - r1) - (x0 - r0)); } else { sRight = 0; // make gcc happy } // solve y(sBottom) + r(sBottom) = yMin if ((haveSBottom = fabs((y1 + r1) - (y0 + r0)) > 0.000001)) { sBottom = (yMin - (y0 + r0)) / ((y1 + r1) - (y0 + r0)); } else { sBottom = 0; // make gcc happy } // solve y(sTop) - r(sTop) = yMax if ((haveSTop = fabs((y1 - r1) - (y0 - r0)) > 0.000001)) { sTop = (yMax - (y0 - r0)) / ((y1 - r1) - (y0 - r0)); } else { sTop = 0; // make gcc happy } // solve r(sZero) = 0 if ((haveSZero = fabs(r1 - r0) > 0.000001)) { sZero = -r0 / (r1 - r0); } else { sZero = 0; // make gcc happy } // solve r(sDiag) = sqrt((xMax-xMin)^2 + (yMax-yMin)^2) if (haveSZero) { sDiag = (sqrt((xMax - xMin) * (xMax - xMin) + (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0); } else { sDiag = 0; // make gcc happy } // compute sMin if (shading->getExtend0()) { sMin = 0; haveSMin = gFalse; if (x0 < x1 && haveSLeft && sLeft < 0) { sMin = sLeft; haveSMin = gTrue; } else if (x0 > x1 && haveSRight && sRight < 0) { sMin = sRight; haveSMin = gTrue; } if (y0 < y1 && haveSBottom && sBottom < 0) { if (!haveSMin || sBottom > sMin) { sMin = sBottom; haveSMin = gTrue; } } else if (y0 > y1 && haveSTop && sTop < 0) { if (!haveSMin || sTop > sMin) { sMin = sTop; haveSMin = gTrue; } } if (haveSZero && sZero < 0) { if (!haveSMin || sZero > sMin) { sMin = sZero; } } } else { sMin = 0; } // compute sMax if (shading->getExtend1()) { sMax = 1; haveSMax = gFalse; if (x1 < x0 && haveSLeft && sLeft > 1) { sMax = sLeft; haveSMax = gTrue; } else if (x1 > x0 && haveSRight && sRight > 1) { sMax = sRight; haveSMax = gTrue; } if (y1 < y0 && haveSBottom && sBottom > 1) { if (!haveSMax || sBottom < sMax) { sMax = sBottom; haveSMax = gTrue; } } else if (y1 > y0 && haveSTop && sTop > 1) { if (!haveSMax || sTop < sMax) { sMax = sTop; haveSMax = gTrue; } } if (haveSZero && sDiag > 1) { if (!haveSMax || sDiag < sMax) { sMax = sDiag; } } } else { sMax = 1; } } // generate the PS code writePSFmt("/x0 {0:.6g} def\n", x0); writePSFmt("/x1 {0:.6g} def\n", x1); writePSFmt("/dx {0:.6g} def\n", x1 - x0); writePSFmt("/y0 {0:.6g} def\n", y0); writePSFmt("/y1 {0:.6g} def\n", y1); writePSFmt("/dy {0:.6g} def\n", y1 - y0); writePSFmt("/r0 {0:.6g} def\n", r0); writePSFmt("/r1 {0:.6g} def\n", r1); writePSFmt("/dr {0:.6g} def\n", r1 - r0); writePSFmt("/t0 {0:.6g} def\n", t0); writePSFmt("/t1 {0:.6g} def\n", t1); writePSFmt("/dt {0:.6g} def\n", t1 - t0); writePSFmt("/n {0:d} def\n", shading->getColorSpace()->getNComps()); writePSFmt("/encl {0:s} def\n", enclosed ? "true" : "false"); writePSFmt("/a1 {0:.6g} def\n", a1); writePSFmt("/a2 {0:.6g} def\n", a2); if (shading->getNFuncs() == 1) { writePS("/func "); cvtFunction(shading->getFunc(0)); writePS("def\n"); } else { writePS("/func {\n"); for (i = 0; i < shading->getNFuncs(); ++i) { if (i < shading->getNFuncs() - 1) { writePS("dup\n"); } cvtFunction(shading->getFunc(i)); writePS("exec\n"); if (i < shading->getNFuncs() - 1) { writePS("exch\n"); } } writePS("} def\n"); } writePSFmt("{0:.6g} {1:.6g} 0 radialSH\n", sMin, sMax); // extend the 'enclosed' case if (enclosed) { // extend the smaller circle if ((shading->getExtend0() && r0 <= r1) || (shading->getExtend1() && r1 < r0)) { if (r0 <= r1) { ta = t0; ra = r0; xa = x0; ya = y0; } else { ta = t1; ra = r1; xa = x1; ya = y1; } if (level == psLevel2Sep || level == psLevel3Sep) { writePSFmt("{0:.6g} radialCol aload pop k\n", ta); } else { writePSFmt("{0:.6g} radialCol sc\n", ta); } writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h f*\n", xa, ya, ra); } // extend the larger circle if ((shading->getExtend0() && r0 > r1) || (shading->getExtend1() && r1 >= r0)) { if (r0 > r1) { ta = t0; ra = r0; xa = x0; ya = y0; } else { ta = t1; ra = r1; xa = x1; ya = y1; } if (level == psLevel2Sep || level == psLevel3Sep) { writePSFmt("{0:.6g} radialCol aload pop k\n", ta); } else { writePSFmt("{0:.6g} radialCol sc\n", ta); } writePSFmt("{0:.6g} {1:.6g} {2:.6g} 0 360 arc h\n", xa, ya, ra); writePSFmt("{0:.6g} {1:.6g} m {2:.6g} {3:.6g} l {4:.6g} {5:.6g} l {6:.6g} {7:.6g} l h f*\n", xMin, yMin, xMin, yMax, xMax, yMax, xMax, yMin); } } return gTrue; } void PSOutputDev::clip(GfxState *state) { doPath(state->getPath()); writePS("W\n"); } void PSOutputDev::eoClip(GfxState *state) { doPath(state->getPath()); writePS("W*\n"); } void PSOutputDev::clipToStrokePath(GfxState *state) { doPath(state->getPath()); writePS("Ws\n"); } void PSOutputDev::doPath(GfxPath *path) { GfxSubpath *subpath; double x0, y0, x1, y1, x2, y2, x3, y3, x4, y4; int n, m, i, j; n = path->getNumSubpaths(); if (n == 1 && path->getSubpath(0)->getNumPoints() == 5) { subpath = path->getSubpath(0); x0 = subpath->getX(0); y0 = subpath->getY(0); x4 = subpath->getX(4); y4 = subpath->getY(4); if (x4 == x0 && y4 == y0) { x1 = subpath->getX(1); y1 = subpath->getY(1); x2 = subpath->getX(2); y2 = subpath->getY(2); x3 = subpath->getX(3); y3 = subpath->getY(3); if (x0 == x1 && x2 == x3 && y0 == y3 && y1 == y2) { writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n", x0 < x2 ? x0 : x2, y0 < y1 ? y0 : y1, fabs(x2 - x0), fabs(y1 - y0)); return; } else if (x0 == x3 && x1 == x2 && y0 == y1 && y2 == y3) { writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} re\n", x0 < x1 ? x0 : x1, y0 < y2 ? y0 : y2, fabs(x1 - x0), fabs(y2 - y0)); return; } } } for (i = 0; i < n; ++i) { subpath = path->getSubpath(i); m = subpath->getNumPoints(); writePSFmt("{0:.6g} {1:.6g} m\n", subpath->getX(0), subpath->getY(0)); j = 1; while (j < m) { if (subpath->getCurve(j)) { writePSFmt("{0:.6g} {1:.6g} {2:.6g} {3:.6g} {4:.6g} {5:.6g} c\n", subpath->getX(j), subpath->getY(j), subpath->getX(j+1), subpath->getY(j+1), subpath->getX(j+2), subpath->getY(j+2)); j += 3; } else { writePSFmt("{0:.6g} {1:.6g} l\n", subpath->getX(j), subpath->getY(j)); ++j; } } if (subpath->isClosed()) { writePS("h\n"); } } } void PSOutputDev::drawString(GfxState *state, GString *s) { GfxFont *font; int wMode; int *codeToGID; GString *s2; double dx, dy, originX, originY; char *p; UnicodeMap *uMap; CharCode code; Unicode u[8]; char buf[8]; double *dxdy; int dxdySize, len, nChars, uLen, n, m, i, j; // check for invisible text -- this is used by Acrobat Capture if (state->getRender() == 3) { return; } // ignore empty strings if (s->getLength() == 0) { return; } // get the font if (!(font = state->getFont())) { return; } wMode = font->getWMode(); // check for a subtitute 16-bit font uMap = NULL; codeToGID = NULL; if (font->isCIDFont()) { for (i = 0; i < font16EncLen; ++i) { if (font->getID()->num == font16Enc[i].fontID.num && font->getID()->gen == font16Enc[i].fontID.gen) { if (!font16Enc[i].enc) { // font substitution failed, so don't output any text return; } uMap = globalParams->getUnicodeMap(font16Enc[i].enc); break; } } // check for a code-to-GID map } else { for (i = 0; i < font8InfoLen; ++i) { if (font->getID()->num == font8Info[i].fontID.num && font->getID()->gen == font8Info[i].fontID.gen) { codeToGID = font8Info[i].codeToGID; break; } } } // compute the positioning (dx, dy) for each char in the string nChars = 0; p = s->getCString(); len = s->getLength(); s2 = new GString(); dxdySize = font->isCIDFont() ? 8 : s->getLength(); dxdy = (double *)gmallocn(2 * dxdySize, sizeof(double)); while (len > 0) { n = font->getNextChar(p, len, &code, u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, &dx, &dy, &originX, &originY); dx *= state->getFontSize(); dy *= state->getFontSize(); if (wMode) { dy += state->getCharSpace(); if (n == 1 && *p == ' ') { dy += state->getWordSpace(); } } else { dx += state->getCharSpace(); if (n == 1 && *p == ' ') { dx += state->getWordSpace(); } } dx *= state->getHorizScaling(); if (font->isCIDFont()) { if (uMap) { if (nChars + uLen > dxdySize) { do { dxdySize *= 2; } while (nChars + uLen > dxdySize); dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); } for (i = 0; i < uLen; ++i) { m = uMap->mapUnicode(u[i], buf, (int)sizeof(buf)); for (j = 0; j < m; ++j) { s2->append(buf[j]); } //~ this really needs to get the number of chars in the target //~ encoding - which may be more than the number of Unicode //~ chars dxdy[2 * nChars] = dx; dxdy[2 * nChars + 1] = dy; ++nChars; } } else { if (nChars + 1 > dxdySize) { dxdySize *= 2; dxdy = (double *)greallocn(dxdy, 2 * dxdySize, sizeof(double)); } s2->append((char)((code >> 8) & 0xff)); s2->append((char)(code & 0xff)); dxdy[2 * nChars] = dx; dxdy[2 * nChars + 1] = dy; ++nChars; } } else { if (!codeToGID || codeToGID[code] >= 0) { s2->append((char)code); dxdy[2 * nChars] = dx; dxdy[2 * nChars + 1] = dy; ++nChars; } } p += n; len -= n; } if (uMap) { uMap->decRefCnt(); } if (nChars > 0) { writePSString(s2); writePS("\n["); for (i = 0; i < 2 * nChars; ++i) { if (i > 0) { writePS("\n"); } writePSFmt("{0:.6g}", dxdy[i]); } writePS("] Tj\n"); } gfree(dxdy); delete s2; if (state->getRender() & 4) { haveTextClip = gTrue; } } void PSOutputDev::endTextObject(GfxState *state) { if (haveTextClip) { writePS("Tclip\n"); haveTextClip = gFalse; } } void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { int len; len = height * ((width + 7) / 8); switch (level) { case psLevel1: case psLevel1Sep: doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); break; case psLevel2: case psLevel2Sep: doImageL2(ref, NULL, invert, inlineImg, str, width, height, len, NULL, NULL, 0, 0, gFalse); break; case psLevel3: case psLevel3Sep: doImageL3(ref, NULL, invert, inlineImg, str, width, height, len, NULL, NULL, 0, 0, gFalse); break; } } void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { int len; len = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); switch (level) { case psLevel1: doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len); break; case psLevel1Sep: //~ handle indexed, separation, ... color spaces doImageL1Sep(colorMap, gFalse, inlineImg, str, width, height, len); break; case psLevel2: case psLevel2Sep: doImageL2(ref, colorMap, gFalse, inlineImg, str, width, height, len, maskColors, NULL, 0, 0, gFalse); break; case psLevel3: case psLevel3Sep: doImageL3(ref, colorMap, gFalse, inlineImg, str, width, height, len, maskColors, NULL, 0, 0, gFalse); break; } t3Cacheable = gFalse; } void PSOutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { int len; len = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); switch (level) { case psLevel1: doImageL1(ref, colorMap, gFalse, gFalse, str, width, height, len); break; case psLevel1Sep: //~ handle indexed, separation, ... color spaces doImageL1Sep(colorMap, gFalse, gFalse, str, width, height, len); break; case psLevel2: case psLevel2Sep: doImageL2(ref, colorMap, gFalse, gFalse, str, width, height, len, NULL, maskStr, maskWidth, maskHeight, maskInvert); break; case psLevel3: case psLevel3Sep: doImageL3(ref, colorMap, gFalse, gFalse, str, width, height, len, NULL, maskStr, maskWidth, maskHeight, maskInvert); break; } t3Cacheable = gFalse; } void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len) { ImageStream *imgStr; Guchar pixBuf[gfxColorMaxComps]; GfxGray gray; int col, x, y, c, i; if ((inType3Char || preload) && !colorMap) { if (inlineImg) { // create an array str = new FixedLengthEncoder(str, len); str = new ASCIIHexEncoder(str); str->reset(); col = 0; writePS("[<"); do { do { c = str->getChar(); } while (c == '\n' || c == '\r'); if (c == '>' || c == EOF) { break; } writePSChar(c); ++col; // each line is: "<...data...>" // so max data length = 255 - 4 = 251 // but make it 240 just to be safe // chunks are 2 bytes each, so we need to stop on an even col number if (col == 240) { writePS(">\n<"); col = 0; } } while (c != '>' && c != EOF); writePS(">]\n"); writePS("0\n"); str->close(); delete str; } else { // set up to use the array already created by setupImages() writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); } } // image/imagemask command if ((inType3Char || preload) && !colorMap) { writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1a\n", width, height, invert ? "true" : "false", width, -height, height); } else if (colorMap) { writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1\n", width, height, width, -height, height); } else { writePSFmt("{0:d} {1:d} {2:s} [{3:d} 0 0 {4:d} 0 {5:d}] pdfImM1\n", width, height, invert ? "true" : "false", width, -height, height); } // image data if (!((inType3Char || preload) && !colorMap)) { if (colorMap) { // set up to process the data stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); // process the data stream i = 0; for (y = 0; y < height; ++y) { // write the line for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); colorMap->getGray(pixBuf, &gray); writePSFmt("{0:02x}", colToByte(gray)); if (++i == 32) { writePSChar('\n'); i = 0; } } } if (i != 0) { writePSChar('\n'); } str->close(); delete imgStr; // imagemask } else { str->reset(); i = 0; for (y = 0; y < height; ++y) { for (x = 0; x < width; x += 8) { writePSFmt("{0:02x}", str->getChar() & 0xff); if (++i == 32) { writePSChar('\n'); i = 0; } } } if (i != 0) { writePSChar('\n'); } str->close(); } } } void PSOutputDev::doImageL1Sep(GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len) { ImageStream *imgStr; Guchar *lineBuf; Guchar pixBuf[gfxColorMaxComps]; GfxCMYK cmyk; int x, y, i, comp; // width, height, matrix, bits per component writePSFmt("{0:d} {1:d} 8 [{2:d} 0 0 {3:d} 0 {4:d}] pdfIm1Sep\n", width, height, width, -height, height); // allocate a line buffer lineBuf = (Guchar *)gmallocn(width, 4); // set up to process the data stream imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), colorMap->getBits()); imgStr->reset(); // process the data stream i = 0; for (y = 0; y < height; ++y) { // read the line for (x = 0; x < width; ++x) { imgStr->getPixel(pixBuf); colorMap->getCMYK(pixBuf, &cmyk); lineBuf[4*x+0] = colToByte(cmyk.c); lineBuf[4*x+1] = colToByte(cmyk.m); lineBuf[4*x+2] = colToByte(cmyk.y); lineBuf[4*x+3] = colToByte(cmyk.k); addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k)); } // write one line of each color component for (comp = 0; comp < 4; ++comp) { for (x = 0; x < width; ++x) { writePSFmt("{0:02x}", lineBuf[4*x + comp]); if (++i == 32) { writePSChar('\n'); i = 0; } } } } if (i != 0) { writePSChar('\n'); } str->close(); delete imgStr; gfree(lineBuf); } void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len, int *maskColors, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { Stream *str2; ImageStream *imgStr; Guchar *line; PSOutImgClipRect *rects0, *rects1, *rectsTmp, *rectsOut; int rects0Len, rects1Len, rectsSize, rectsOutLen, rectsOutSize; GBool emitRect, addRect, extendRect; GString *s; int n, numComps; GBool useRLE, useASCII, useASCIIHex, useCompressed; GfxSeparationColorSpace *sepCS; GfxColor color; GfxCMYK cmyk; int c; int col, i, j, x0, x1, y, maskXor; // color key masking if (maskColors && colorMap && !inlineImg) { // can't read the stream twice for inline images -- but masking // isn't allowed with inline images anyway numComps = colorMap->getNumPixelComps(); imgStr = new ImageStream(str, width, numComps, colorMap->getBits()); imgStr->reset(); rects0Len = rects1Len = rectsOutLen = 0; rectsSize = rectsOutSize = 64; rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect)); for (y = 0; y < height; ++y) { if (!(line = imgStr->getLine())) { break; } i = 0; rects1Len = 0; for (x0 = 0; x0 < width; ++x0) { for (j = 0; j < numComps; ++j) { if (line[x0*numComps+j] < maskColors[2*j] || line[x0*numComps+j] > maskColors[2*j+1]) { break; } } if (j < numComps) { break; } } for (x1 = x0; x1 < width; ++x1) { for (j = 0; j < numComps; ++j) { if (line[x1*numComps+j] < maskColors[2*j] || line[x1*numComps+j] > maskColors[2*j+1]) { break; } } if (j == numComps) { break; } } while (x0 < width || i < rects0Len) { emitRect = addRect = extendRect = gFalse; if (x0 >= width) { emitRect = gTrue; } else if (i >= rects0Len) { addRect = gTrue; } else if (rects0[i].x0 < x0) { emitRect = gTrue; } else if (x0 < rects0[i].x0) { addRect = gTrue; } else if (rects0[i].x1 == x1) { extendRect = gTrue; } else { emitRect = addRect = gTrue; } if (emitRect) { if (rectsOutLen == rectsOutSize) { rectsOutSize *= 2; rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); } rectsOut[rectsOutLen].x0 = rects0[i].x0; rectsOut[rectsOutLen].x1 = rects0[i].x1; rectsOut[rectsOutLen].y0 = height - y - 1; rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1; ++rectsOutLen; ++i; } if (addRect || extendRect) { if (rects1Len == rectsSize) { rectsSize *= 2; rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect)); rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect)); } rects1[rects1Len].x0 = x0; rects1[rects1Len].x1 = x1; if (addRect) { rects1[rects1Len].y0 = y; } if (extendRect) { rects1[rects1Len].y0 = rects0[i].y0; ++i; } ++rects1Len; for (x0 = x1; x0 < width; ++x0) { for (j = 0; j < numComps; ++j) { if (line[x0*numComps+j] < maskColors[2*j] || line[x0*numComps+j] > maskColors[2*j+1]) { break; } } if (j < numComps) { break; } } for (x1 = x0; x1 < width; ++x1) { for (j = 0; j < numComps; ++j) { if (line[x1*numComps+j] < maskColors[2*j] || line[x1*numComps+j] > maskColors[2*j+1]) { break; } } if (j == numComps) { break; } } } } rectsTmp = rects0; rects0 = rects1; rects1 = rectsTmp; i = rects0Len; rects0Len = rects1Len; rects1Len = i; } for (i = 0; i < rects0Len; ++i) { if (rectsOutLen == rectsOutSize) { rectsOutSize *= 2; rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); } rectsOut[rectsOutLen].x0 = rects0[i].x0; rectsOut[rectsOutLen].x1 = rects0[i].x1; rectsOut[rectsOutLen].y0 = height - y - 1; rectsOut[rectsOutLen].y1 = height - rects0[i].y0 - 1; ++rectsOutLen; } writePSFmt("{0:d} array 0\n", rectsOutLen * 4); for (i = 0; i < rectsOutLen; ++i) { writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", rectsOut[i].x0, rectsOut[i].y0, rectsOut[i].x1 - rectsOut[i].x0, rectsOut[i].y1 - rectsOut[i].y0); } writePSFmt("pop {0:d} {1:d} pdfImClip\n", width, height); gfree(rectsOut); gfree(rects0); gfree(rects1); delete imgStr; str->close(); // explicit masking } else if (maskStr) { imgStr = new ImageStream(maskStr, maskWidth, 1, 1); imgStr->reset(); rects0Len = rects1Len = rectsOutLen = 0; rectsSize = rectsOutSize = 64; rects0 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); rects1 = (PSOutImgClipRect *)gmallocn(rectsSize, sizeof(PSOutImgClipRect)); rectsOut = (PSOutImgClipRect *)gmallocn(rectsOutSize, sizeof(PSOutImgClipRect)); maskXor = maskInvert ? 1 : 0; for (y = 0; y < maskHeight; ++y) { if (!(line = imgStr->getLine())) { break; } i = 0; rects1Len = 0; for (x0 = 0; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; while (x0 < maskWidth || i < rects0Len) { emitRect = addRect = extendRect = gFalse; if (x0 >= maskWidth) { emitRect = gTrue; } else if (i >= rects0Len) { addRect = gTrue; } else if (rects0[i].x0 < x0) { emitRect = gTrue; } else if (x0 < rects0[i].x0) { addRect = gTrue; } else if (rects0[i].x1 == x1) { extendRect = gTrue; } else { emitRect = addRect = gTrue; } if (emitRect) { if (rectsOutLen == rectsOutSize) { rectsOutSize *= 2; rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); } rectsOut[rectsOutLen].x0 = rects0[i].x0; rectsOut[rectsOutLen].x1 = rects0[i].x1; rectsOut[rectsOutLen].y0 = maskHeight - y - 1; rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; ++rectsOutLen; ++i; } if (addRect || extendRect) { if (rects1Len == rectsSize) { rectsSize *= 2; rects0 = (PSOutImgClipRect *)greallocn(rects0, rectsSize, sizeof(PSOutImgClipRect)); rects1 = (PSOutImgClipRect *)greallocn(rects1, rectsSize, sizeof(PSOutImgClipRect)); } rects1[rects1Len].x0 = x0; rects1[rects1Len].x1 = x1; if (addRect) { rects1[rects1Len].y0 = y; } if (extendRect) { rects1[rects1Len].y0 = rects0[i].y0; ++i; } ++rects1Len; for (x0 = x1; x0 < maskWidth && (line[x0] ^ maskXor); ++x0) ; for (x1 = x0; x1 < maskWidth && !(line[x1] ^ maskXor); ++x1) ; } } rectsTmp = rects0; rects0 = rects1; rects1 = rectsTmp; i = rects0Len; rects0Len = rects1Len; rects1Len = i; } for (i = 0; i < rects0Len; ++i) { if (rectsOutLen == rectsOutSize) { rectsOutSize *= 2; rectsOut = (PSOutImgClipRect *)greallocn(rectsOut, rectsOutSize, sizeof(PSOutImgClipRect)); } rectsOut[rectsOutLen].x0 = rects0[i].x0; rectsOut[rectsOutLen].x1 = rects0[i].x1; rectsOut[rectsOutLen].y0 = maskHeight - y - 1; rectsOut[rectsOutLen].y1 = maskHeight - rects0[i].y0 - 1; ++rectsOutLen; } writePSFmt("{0:d} array 0\n", rectsOutLen * 4); for (i = 0; i < rectsOutLen; ++i) { writePSFmt("[{0:d} {1:d} {2:d} {3:d}] pr\n", rectsOut[i].x0, rectsOut[i].y0, rectsOut[i].x1 - rectsOut[i].x0, rectsOut[i].y1 - rectsOut[i].y0); } writePSFmt("pop {0:d} {1:d} pdfImClip\n", maskWidth, maskHeight); gfree(rectsOut); gfree(rects0); gfree(rects1); delete imgStr; maskStr->close(); } // color space if (colorMap) { dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse); writePS(" setcolorspace\n"); } useASCIIHex = globalParams->getPSASCIIHex(); // set up the image data if (mode == psModeForm || inType3Char || preload) { if (inlineImg) { // create an array str2 = new FixedLengthEncoder(str, len); str2 = new RunLengthEncoder(str2); if (useASCIIHex) { str2 = new ASCIIHexEncoder(str2); } else { str2 = new ASCII85Encoder(str2); } str2->reset(); col = 0; writePS((char *)(useASCIIHex ? "[<" : "[<~")); do { do { c = str2->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { writePSChar(c); ++col; } else { writePSChar(c); ++col; for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str2->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } writePSChar(c); ++col; } } // each line is: "<~...data...~>" // so max data length = 255 - 6 = 249 // chunks are 1 or 5 bytes each, so we have to stop at 245 // but make it 240 just to be safe if (col > 240) { writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); col = 0; } } while (c != (useASCIIHex ? '>' : '~') && c != EOF); writePS((char *)(useASCIIHex ? ">\n" : "~>\n")); // add an extra entry because the RunLengthDecode filter may // read past the end writePS("<>]\n"); writePS("0\n"); str2->close(); delete str2; } else { // set up to use the array already created by setupImages() writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); } } // image dictionary writePS("<<\n /ImageType 1\n"); // width, height, matrix, bits per component writePSFmt(" /Width {0:d}\n", width); writePSFmt(" /Height {0:d}\n", height); writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", width, -height, height); if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { writePS(" /BitsPerComponent 8\n"); } else { writePSFmt(" /BitsPerComponent {0:d}\n", colorMap ? colorMap->getBits() : 1); } // decode if (colorMap) { writePS(" /Decode ["); if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap->getColorSpace()->getMode() == csSeparation) { // this matches up with the code in the pdfImSep operator n = (1 << colorMap->getBits()) - 1; writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n, colorMap->getDecodeHigh(0) * n); } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> getAlt()->getNComps(); for (i = 0; i < numComps; ++i) { if (i > 0) { writePS(" "); } writePS("0 1"); } } else { numComps = colorMap->getNumPixelComps(); for (i = 0; i < numComps; ++i) { if (i > 0) { writePS(" "); } writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i)); } } writePS("]\n"); } else { writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1); } // data source if (mode == psModeForm || inType3Char || preload) { writePS(" /DataSource { pdfImStr }\n"); } else { writePS(" /DataSource currentfile\n"); } // filters if ((mode == psModeForm || inType3Char || preload) && globalParams->getPSUncompressPreloadedImages()) { s = NULL; useRLE = gFalse; useCompressed = gFalse; useASCII = gFalse; } else { s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, " "); if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || inlineImg || !s) { useRLE = gTrue; useASCII = !(mode == psModeForm || inType3Char || preload); useCompressed = gFalse; } else { useRLE = gFalse; useASCII = str->isBinary() && !(mode == psModeForm || inType3Char || preload); useCompressed = gTrue; } } if (useASCII) { writePSFmt(" /ASCII{0:s}Decode filter\n", useASCIIHex ? "Hex" : "85"); } if (useRLE) { writePS(" /RunLengthDecode filter\n"); } if (useCompressed) { writePS(s->getCString()); } if (s) { delete s; } if (mode == psModeForm || inType3Char || preload) { // end of image dictionary writePSFmt(">>\n{0:s}\n", colorMap ? "image" : "imagemask"); // get rid of the array and index writePS("pop pop\n"); } else { // cut off inline image streams at appropriate length if (inlineImg) { str = new FixedLengthEncoder(str, len); } else if (useCompressed) { str = str->getUndecodedStream(); } // recode DeviceN data if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { str = new DeviceNRecoder(str, width, height, colorMap); } // add RunLengthEncode and ASCIIHex/85 encode filters if (useRLE) { str = new RunLengthEncoder(str); } if (useASCII) { if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); } } // end of image dictionary writePS(">>\n"); #if OPI_SUPPORT if (opi13Nest) { if (inlineImg) { // this can't happen -- OPI dictionaries are in XObjects error(errSyntaxError, -1, "OPI in inline image"); n = 0; } else { // need to read the stream to count characters -- the length // is data-dependent (because of ASCII and RLE filters) str->reset(); n = 0; while ((c = str->getChar()) != EOF) { ++n; } str->close(); } // +6/7 for "pdfIm\n" / "pdfImM\n" // +8 for newline + trailer n += colorMap ? 14 : 15; writePSFmt("%%BeginData: {0:d} Hex Bytes\n", n); } #endif if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && colorMap->getColorSpace()->getMode() == csSeparation) { color.c[0] = gfxColorComp1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n", colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()); } else { writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM"); } // copy the stream data str->reset(); while ((c = str->getChar()) != EOF) { writePSChar(c); } str->close(); // add newline and trailer to the end writePSChar('\n'); writePS("%-EOD-\n"); #if OPI_SUPPORT if (opi13Nest) { writePS("%%EndData\n"); } #endif // delete encoders if (useRLE || useASCII || inlineImg) { delete str; } } if ((maskColors && colorMap && !inlineImg) || maskStr) { writePS("pdfImClipEnd\n"); } } //~ this doesn't currently support OPI void PSOutputDev::doImageL3(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len, int *maskColors, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { Stream *str2; GString *s; int n, numComps; GBool useRLE, useASCII, useASCIIHex, useCompressed; GBool maskUseRLE, maskUseASCII, maskUseCompressed; GString *maskFilters; GfxSeparationColorSpace *sepCS; GfxColor color; GfxCMYK cmyk; int c; int col, i; useASCIIHex = globalParams->getPSASCIIHex(); useRLE = useASCII = useCompressed = gFalse; // make gcc happy maskUseRLE = maskUseASCII = maskUseCompressed = gFalse; // make gcc happy maskFilters = NULL; // make gcc happy // explicit masking if (maskStr) { // mask data source if ((mode == psModeForm || inType3Char || preload) && globalParams->getPSUncompressPreloadedImages()) { s = NULL; maskUseRLE = gFalse; maskUseCompressed = gFalse; maskUseASCII = gFalse; } else { s = maskStr->getPSFilter(3, " "); if (!s) { maskUseRLE = gTrue; maskUseASCII = !(mode == psModeForm || inType3Char || preload); maskUseCompressed = gFalse; } else { maskUseRLE = gFalse; maskUseASCII = maskStr->isBinary() && !(mode == psModeForm || inType3Char || preload); maskUseCompressed = gTrue; } } maskFilters = new GString(); if (maskUseASCII) { maskFilters->appendf(" /ASCII{0:s}Decode filter\n", useASCIIHex ? "Hex" : "85"); } if (maskUseRLE) { maskFilters->append(" /RunLengthDecode filter\n"); } if (maskUseCompressed) { maskFilters->append(s); } if (s) { delete s; } if (mode == psModeForm || inType3Char || preload) { writePSFmt("MaskData_{0:d}_{1:d} pdfMaskInit\n", ref->getRefNum(), ref->getRefGen()); } else { writePS("currentfile\n"); writePS(maskFilters->getCString()); writePS("pdfMask\n"); // add RunLengthEncode and ASCIIHex/85 encode filters if (maskUseCompressed) { maskStr = maskStr->getUndecodedStream(); } if (maskUseRLE) { maskStr = new RunLengthEncoder(maskStr); } if (maskUseASCII) { if (useASCIIHex) { maskStr = new ASCIIHexEncoder(maskStr); } else { maskStr = new ASCII85Encoder(maskStr); } } // copy the stream data maskStr->reset(); while ((c = maskStr->getChar()) != EOF) { writePSChar(c); } maskStr->close(); writePSChar('\n'); writePS("%-EOD-\n"); // delete encoders if (maskUseRLE || maskUseASCII) { delete maskStr; } } } // color space if (colorMap) { dumpColorSpaceL2(colorMap->getColorSpace(), gFalse, gTrue, gFalse); writePS(" setcolorspace\n"); } // set up the image data if (mode == psModeForm || inType3Char || preload) { if (inlineImg) { // create an array str2 = new FixedLengthEncoder(str, len); str2 = new RunLengthEncoder(str2); if (useASCIIHex) { str2 = new ASCIIHexEncoder(str2); } else { str2 = new ASCII85Encoder(str2); } str2->reset(); col = 0; writePS((char *)(useASCIIHex ? "[<" : "[<~")); do { do { c = str2->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { writePSChar(c); ++col; } else { writePSChar(c); ++col; for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str2->getChar(); } while (c == '\n' || c == '\r'); if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } writePSChar(c); ++col; } } // each line is: "<~...data...~>" // so max data length = 255 - 6 = 249 // chunks are 1 or 5 bytes each, so we have to stop at 245 // but make it 240 just to be safe if (col > 240) { writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); col = 0; } } while (c != (useASCIIHex ? '>' : '~') && c != EOF); writePS((char *)(useASCIIHex ? ">\n" : "~>\n")); // add an extra entry because the RunLengthDecode filter may // read past the end writePS("<>]\n"); writePS("0\n"); str2->close(); delete str2; } else { // set up to use the array already created by setupImages() writePSFmt("ImData_{0:d}_{1:d} 0\n", ref->getRefNum(), ref->getRefGen()); } } // explicit masking if (maskStr) { writePS("<<\n /ImageType 3\n"); writePS(" /InterleaveType 3\n"); writePS(" /DataDict\n"); } // image (data) dictionary writePSFmt("<<\n /ImageType {0:d}\n", (maskColors && colorMap) ? 4 : 1); // color key masking if (maskColors && colorMap) { writePS(" /MaskColor [\n"); numComps = colorMap->getNumPixelComps(); for (i = 0; i < 2 * numComps; i += 2) { writePSFmt(" {0:d} {1:d}\n", maskColors[i], maskColors[i+1]); } writePS(" ]\n"); } // width, height, matrix, bits per component writePSFmt(" /Width {0:d}\n", width); writePSFmt(" /Height {0:d}\n", height); writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", width, -height, height); if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { writePS(" /BitsPerComponent 8\n"); } else { writePSFmt(" /BitsPerComponent {0:d}\n", colorMap ? colorMap->getBits() : 1); } // decode if (colorMap) { writePS(" /Decode ["); if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap->getColorSpace()->getMode() == csSeparation) { // this matches up with the code in the pdfImSep operator n = (1 << colorMap->getBits()) - 1; writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(0) * n, colorMap->getDecodeHigh(0) * n); } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> getAlt()->getNComps(); for (i = 0; i < numComps; ++i) { if (i > 0) { writePS(" "); } writePS("0 1"); } } else { numComps = colorMap->getNumPixelComps(); for (i = 0; i < numComps; ++i) { if (i > 0) { writePS(" "); } writePSFmt("{0:.4g} {1:.4g}", colorMap->getDecodeLow(i), colorMap->getDecodeHigh(i)); } } writePS("]\n"); } else { writePSFmt(" /Decode [{0:d} {1:d}]\n", invert ? 1 : 0, invert ? 0 : 1); } // data source if (mode == psModeForm || inType3Char || preload) { writePS(" /DataSource { pdfImStr }\n"); } else { writePS(" /DataSource currentfile\n"); } // filters if ((mode == psModeForm || inType3Char || preload) && globalParams->getPSUncompressPreloadedImages()) { s = NULL; useRLE = gFalse; useCompressed = gFalse; useASCII = gFalse; } else { s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, " "); if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || inlineImg || !s) { useRLE = gTrue; useASCII = !(mode == psModeForm || inType3Char || preload); useCompressed = gFalse; } else { useRLE = gFalse; useASCII = str->isBinary() && !(mode == psModeForm || inType3Char || preload); useCompressed = gTrue; } } if (useASCII) { writePSFmt(" /ASCII{0:s}Decode filter\n", useASCIIHex ? "Hex" : "85"); } if (useRLE) { writePS(" /RunLengthDecode filter\n"); } if (useCompressed) { writePS(s->getCString()); } if (s) { delete s; } // end of image (data) dictionary writePS(">>\n"); // explicit masking if (maskStr) { writePS(" /MaskDict\n"); writePS("<<\n"); writePS(" /ImageType 1\n"); writePSFmt(" /Width {0:d}\n", maskWidth); writePSFmt(" /Height {0:d}\n", maskHeight); writePSFmt(" /ImageMatrix [{0:d} 0 0 {1:d} 0 {2:d}]\n", maskWidth, -maskHeight, maskHeight); writePS(" /BitsPerComponent 1\n"); writePSFmt(" /Decode [{0:d} {1:d}]\n", maskInvert ? 1 : 0, maskInvert ? 0 : 1); // mask data source if (mode == psModeForm || inType3Char || preload) { writePS(" /DataSource {pdfMaskSrc}\n"); writePS(maskFilters->getCString()); } else { writePS(" /DataSource maskStream\n"); } delete maskFilters; writePS(">>\n"); writePS(">>\n"); } if (mode == psModeForm || inType3Char || preload) { // image command writePSFmt("{0:s}\n", colorMap ? "image" : "imagemask"); } else { if ((level == psLevel2Sep || level == psLevel3Sep) && colorMap && colorMap->getColorSpace()->getMode() == csSeparation) { color.c[0] = gfxColorComp1; sepCS = (GfxSeparationColorSpace *)colorMap->getColorSpace(); sepCS->getCMYK(&color, &cmyk); writePSFmt("{0:.4g} {1:.4g} {2:.4g} {3:.4g} ({4:t}) pdfImSep\n", colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k), sepCS->getName()); } else { writePSFmt("{0:s}\n", colorMap ? "pdfIm" : "pdfImM"); } } // get rid of the array and index if (mode == psModeForm || inType3Char || preload) { writePS("pop pop\n"); // image data } else { // cut off inline image streams at appropriate length if (inlineImg) { str = new FixedLengthEncoder(str, len); } else if (useCompressed) { str = str->getUndecodedStream(); } // recode DeviceN data if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { str = new DeviceNRecoder(str, width, height, colorMap); } // add RunLengthEncode and ASCIIHex/85 encode filters if (useRLE) { str = new RunLengthEncoder(str); } if (useASCII) { if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); } } // copy the stream data str->reset(); while ((c = str->getChar()) != EOF) { writePSChar(c); } str->close(); // add newline and trailer to the end writePSChar('\n'); writePS("%-EOD-\n"); // delete encoders if (useRLE || useASCII || inlineImg) { delete str; } } // close the mask stream if (maskStr) { if (!(mode == psModeForm || inType3Char || preload)) { writePS("pdfMaskEnd\n"); } } } void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace, GBool genXform, GBool updateColors, GBool map01) { GfxCalGrayColorSpace *calGrayCS; GfxCalRGBColorSpace *calRGBCS; GfxLabColorSpace *labCS; GfxIndexedColorSpace *indexedCS; GfxSeparationColorSpace *separationCS; GfxDeviceNColorSpace *deviceNCS; GfxColorSpace *baseCS; Guchar *lookup, *p; double x[gfxColorMaxComps], y[gfxColorMaxComps]; double low[gfxColorMaxComps], range[gfxColorMaxComps]; GfxColor color; GfxCMYK cmyk; Function *func; int n, numComps, numAltComps; int byte; int i, j, k; switch (colorSpace->getMode()) { case csDeviceGray: writePS("/DeviceGray"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessBlack; } break; case csCalGray: calGrayCS = (GfxCalGrayColorSpace *)colorSpace; writePS("[/CIEBasedA <<\n"); writePSFmt(" /DecodeA {{{0:.4g} exp}} bind\n", calGrayCS->getGamma()); writePSFmt(" /MatrixA [{0:.4g} {1:.4g} {2:.4g}]\n", calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), calGrayCS->getWhiteZ()); writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", calGrayCS->getWhiteX(), calGrayCS->getWhiteY(), calGrayCS->getWhiteZ()); writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", calGrayCS->getBlackX(), calGrayCS->getBlackY(), calGrayCS->getBlackZ()); writePS(">>]"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessBlack; } break; case csDeviceRGB: writePS("/DeviceRGB"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessCMYK; } break; case csCalRGB: calRGBCS = (GfxCalRGBColorSpace *)colorSpace; writePS("[/CIEBasedABC <<\n"); writePSFmt(" /DecodeABC [{{{0:.4g} exp}} bind {{{1:.4g} exp}} bind {{{2:.4g} exp}} bind]\n", calRGBCS->getGammaR(), calRGBCS->getGammaG(), calRGBCS->getGammaB()); writePSFmt(" /MatrixABC [{0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g} {8:.4g}]\n", calRGBCS->getMatrix()[0], calRGBCS->getMatrix()[1], calRGBCS->getMatrix()[2], calRGBCS->getMatrix()[3], calRGBCS->getMatrix()[4], calRGBCS->getMatrix()[5], calRGBCS->getMatrix()[6], calRGBCS->getMatrix()[7], calRGBCS->getMatrix()[8]); writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", calRGBCS->getWhiteX(), calRGBCS->getWhiteY(), calRGBCS->getWhiteZ()); writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", calRGBCS->getBlackX(), calRGBCS->getBlackY(), calRGBCS->getBlackZ()); writePS(">>]"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessCMYK; } break; case csDeviceCMYK: writePS("/DeviceCMYK"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessCMYK; } break; case csLab: labCS = (GfxLabColorSpace *)colorSpace; writePS("[/CIEBasedABC <<\n"); if (map01) { writePS(" /RangeABC [0 1 0 1 0 1]\n"); writePSFmt(" /DecodeABC [{{100 mul 16 add 116 div}} bind {{{0:.4g} mul {1:.4g} add}} bind {{{2:.4g} mul {3:.4g} add}} bind]\n", (labCS->getAMax() - labCS->getAMin()) / 500.0, labCS->getAMin() / 500.0, (labCS->getBMax() - labCS->getBMin()) / 200.0, labCS->getBMin() / 200.0); } else { writePSFmt(" /RangeABC [0 100 {0:.4g} {1:.4g} {2:.4g} {3:.4g}]\n", labCS->getAMin(), labCS->getAMax(), labCS->getBMin(), labCS->getBMax()); writePS(" /DecodeABC [{16 add 116 div} bind {500 div} bind {200 div} bind]\n"); } writePS(" /MatrixABC [1 1 1 1 0 0 0 0 -1]\n"); writePS(" /DecodeLMN\n"); writePS(" [{dup 6 29 div ge {dup dup mul mul}\n"); writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n", labCS->getWhiteX()); writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind\n", labCS->getWhiteY()); writePS(" {dup 6 29 div ge {dup dup mul mul}\n"); writePSFmt(" {{4 29 div sub 108 841 div mul }} ifelse {0:.4g} mul}} bind]\n", labCS->getWhiteZ()); writePSFmt(" /WhitePoint [{0:.4g} {1:.4g} {2:.4g}]\n", labCS->getWhiteX(), labCS->getWhiteY(), labCS->getWhiteZ()); writePSFmt(" /BlackPoint [{0:.4g} {1:.4g} {2:.4g}]\n", labCS->getBlackX(), labCS->getBlackY(), labCS->getBlackZ()); writePS(">>]"); if (genXform) { writePS(" {}"); } if (updateColors) { processColors |= psProcessCMYK; } break; case csICCBased: // there is no transform function to the alternate color space, so // we can use it directly dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt(), genXform, updateColors, gFalse); break; case csIndexed: indexedCS = (GfxIndexedColorSpace *)colorSpace; baseCS = indexedCS->getBase(); writePS("[/Indexed "); dumpColorSpaceL2(baseCS, gFalse, gFalse, gTrue); n = indexedCS->getIndexHigh(); numComps = baseCS->getNComps(); lookup = indexedCS->getLookup(); writePSFmt(" {0:d} <\n", n); if (baseCS->getMode() == csDeviceN) { func = ((GfxDeviceNColorSpace *)baseCS)->getTintTransformFunc(); baseCS->getDefaultRanges(low, range, indexedCS->getIndexHigh()); if (((GfxDeviceNColorSpace *)baseCS)->getAlt()->getMode() == csLab) { labCS = (GfxLabColorSpace *)((GfxDeviceNColorSpace *)baseCS)->getAlt(); } else { labCS = NULL; } numAltComps = ((GfxDeviceNColorSpace *)baseCS)->getAlt()->getNComps(); p = lookup; for (i = 0; i <= n; i += 8) { writePS(" "); for (j = i; j < i+8 && j <= n; ++j) { for (k = 0; k < numComps; ++k) { x[k] = low[k] + (*p++ / 255.0) * range[k]; } func->transform(x, y); if (labCS) { y[0] /= 100.0; y[1] = (y[1] - labCS->getAMin()) / (labCS->getAMax() - labCS->getAMin()); y[2] = (y[2] - labCS->getBMin()) / (labCS->getBMax() - labCS->getBMin()); } for (k = 0; k < numAltComps; ++k) { byte = (int)(y[k] * 255 + 0.5); if (byte < 0) { byte = 0; } else if (byte > 255) { byte = 255; } writePSFmt("{0:02x}", byte); } if (updateColors) { color.c[0] = dblToCol(j); indexedCS->getCMYK(&color, &cmyk); addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k)); } } writePS("\n"); } } else { for (i = 0; i <= n; i += 8) { writePS(" "); for (j = i; j < i+8 && j <= n; ++j) { for (k = 0; k < numComps; ++k) { writePSFmt("{0:02x}", lookup[j * numComps + k]); } if (updateColors) { color.c[0] = dblToCol(j); indexedCS->getCMYK(&color, &cmyk); addProcessColor(colToDbl(cmyk.c), colToDbl(cmyk.m), colToDbl(cmyk.y), colToDbl(cmyk.k)); } } writePS("\n"); } } writePS(">]"); if (genXform) { writePS(" {}"); } break; case csSeparation: separationCS = (GfxSeparationColorSpace *)colorSpace; writePS("[/Separation "); writePSString(separationCS->getName()); writePS(" "); dumpColorSpaceL2(separationCS->getAlt(), gFalse, gFalse, gFalse); writePS("\n"); cvtFunction(separationCS->getFunc()); writePS("]"); if (genXform) { writePS(" {}"); } if (updateColors) { addCustomColor(separationCS); } break; case csDeviceN: // DeviceN color spaces are a Level 3 PostScript feature. deviceNCS = (GfxDeviceNColorSpace *)colorSpace; dumpColorSpaceL2(deviceNCS->getAlt(), gFalse, updateColors, map01); if (genXform) { writePS(" "); cvtFunction(deviceNCS->getTintTransformFunc()); } break; case csPattern: //~ unimplemented break; } } #if OPI_SUPPORT void PSOutputDev::opiBegin(GfxState *state, Dict *opiDict) { Object dict; if (globalParams->getPSOPI()) { opiDict->lookup("2.0", &dict); if (dict.isDict()) { opiBegin20(state, dict.getDict()); dict.free(); } else { dict.free(); opiDict->lookup("1.3", &dict); if (dict.isDict()) { opiBegin13(state, dict.getDict()); } dict.free(); } } } void PSOutputDev::opiBegin20(GfxState *state, Dict *dict) { Object obj1, obj2, obj3, obj4; double width, height, left, right, top, bottom; int w, h; int i; writePS("%%BeginOPI: 2.0\n"); writePS("%%Distilled\n"); dict->lookup("F", &obj1); if (getFileSpec(&obj1, &obj2)) { writePSFmt("%%ImageFileName: {0:t}\n", obj2.getString()); obj2.free(); } obj1.free(); dict->lookup("MainImage", &obj1); if (obj1.isString()) { writePSFmt("%%MainImage: {0:t}\n", obj1.getString()); } obj1.free(); //~ ignoring 'Tags' entry //~ need to use writePSString() and deal with >255-char lines dict->lookup("Size", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { obj1.arrayGet(0, &obj2); width = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); height = obj2.getNum(); obj2.free(); writePSFmt("%%ImageDimensions: {0:.6g} {1:.6g}\n", width, height); } obj1.free(); dict->lookup("CropRect", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 4) { obj1.arrayGet(0, &obj2); left = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); top = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); right = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); bottom = obj2.getNum(); obj2.free(); writePSFmt("%%ImageCropRect: {0:.6g} {1:.6g} {2:.6g} {3:.6g}\n", left, top, right, bottom); } obj1.free(); dict->lookup("Overprint", &obj1); if (obj1.isBool()) { writePSFmt("%%ImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false"); } obj1.free(); dict->lookup("Inks", &obj1); if (obj1.isName()) { writePSFmt("%%ImageInks: {0:s}\n", obj1.getName()); } else if (obj1.isArray() && obj1.arrayGetLength() >= 1) { obj1.arrayGet(0, &obj2); if (obj2.isName()) { writePSFmt("%%ImageInks: {0:s} {1:d}", obj2.getName(), (obj1.arrayGetLength() - 1) / 2); for (i = 1; i+1 < obj1.arrayGetLength(); i += 2) { obj1.arrayGet(i, &obj3); obj1.arrayGet(i+1, &obj4); if (obj3.isString() && obj4.isNum()) { writePS(" "); writePSString(obj3.getString()); writePSFmt(" {0:.4g}", obj4.getNum()); } obj3.free(); obj4.free(); } writePS("\n"); } obj2.free(); } obj1.free(); writePS("gsave\n"); writePS("%%BeginIncludedImage\n"); dict->lookup("IncludedImageDimensions", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { obj1.arrayGet(0, &obj2); w = obj2.getInt(); obj2.free(); obj1.arrayGet(1, &obj2); h = obj2.getInt(); obj2.free(); writePSFmt("%%IncludedImageDimensions: {0:d} {1:d}\n", w, h); } obj1.free(); dict->lookup("IncludedImageQuality", &obj1); if (obj1.isNum()) { writePSFmt("%%IncludedImageQuality: {0:.4g}\n", obj1.getNum()); } obj1.free(); ++opi20Nest; } void PSOutputDev::opiBegin13(GfxState *state, Dict *dict) { Object obj1, obj2; int left, right, top, bottom, samples, bits, width, height; double c, m, y, k; double llx, lly, ulx, uly, urx, ury, lrx, lry; double tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry; double horiz, vert; int i, j; writePS("save\n"); writePS("/opiMatrix2 matrix currentmatrix def\n"); writePS("opiMatrix setmatrix\n"); dict->lookup("F", &obj1); if (getFileSpec(&obj1, &obj2)) { writePSFmt("%ALDImageFileName: {0:t}\n", obj2.getString()); obj2.free(); } obj1.free(); dict->lookup("CropRect", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 4) { obj1.arrayGet(0, &obj2); left = obj2.getInt(); obj2.free(); obj1.arrayGet(1, &obj2); top = obj2.getInt(); obj2.free(); obj1.arrayGet(2, &obj2); right = obj2.getInt(); obj2.free(); obj1.arrayGet(3, &obj2); bottom = obj2.getInt(); obj2.free(); writePSFmt("%ALDImageCropRect: {0:d} {1:d} {2:d} {3:d}\n", left, top, right, bottom); } obj1.free(); dict->lookup("Color", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 5) { obj1.arrayGet(0, &obj2); c = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); m = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); y = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); k = obj2.getNum(); obj2.free(); obj1.arrayGet(4, &obj2); if (obj2.isString()) { writePSFmt("%ALDImageColor: {0:.4g} {1:.4g} {2:.4g} {3:.4g} ", c, m, y, k); writePSString(obj2.getString()); writePS("\n"); } obj2.free(); } obj1.free(); dict->lookup("ColorType", &obj1); if (obj1.isName()) { writePSFmt("%ALDImageColorType: {0:s}\n", obj1.getName()); } obj1.free(); //~ ignores 'Comments' entry //~ need to handle multiple lines dict->lookup("CropFixed", &obj1); if (obj1.isArray()) { obj1.arrayGet(0, &obj2); ulx = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); uly = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); lrx = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); lry = obj2.getNum(); obj2.free(); writePSFmt("%ALDImageCropFixed: {0:.4g} {1:.4g} {2:.4g} {3:.4g}\n", ulx, uly, lrx, lry); } obj1.free(); dict->lookup("GrayMap", &obj1); if (obj1.isArray()) { writePS("%ALDImageGrayMap:"); for (i = 0; i < obj1.arrayGetLength(); i += 16) { if (i > 0) { writePS("\n%%+"); } for (j = 0; j < 16 && i+j < obj1.arrayGetLength(); ++j) { obj1.arrayGet(i+j, &obj2); writePSFmt(" {0:d}", obj2.getInt()); obj2.free(); } } writePS("\n"); } obj1.free(); dict->lookup("ID", &obj1); if (obj1.isString()) { writePSFmt("%ALDImageID: {0:t}\n", obj1.getString()); } obj1.free(); dict->lookup("ImageType", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { obj1.arrayGet(0, &obj2); samples = obj2.getInt(); obj2.free(); obj1.arrayGet(1, &obj2); bits = obj2.getInt(); obj2.free(); writePSFmt("%ALDImageType: {0:d} {1:d}\n", samples, bits); } obj1.free(); dict->lookup("Overprint", &obj1); if (obj1.isBool()) { writePSFmt("%ALDImageOverprint: {0:s}\n", obj1.getBool() ? "true" : "false"); } obj1.free(); dict->lookup("Position", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 8) { obj1.arrayGet(0, &obj2); llx = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); lly = obj2.getNum(); obj2.free(); obj1.arrayGet(2, &obj2); ulx = obj2.getNum(); obj2.free(); obj1.arrayGet(3, &obj2); uly = obj2.getNum(); obj2.free(); obj1.arrayGet(4, &obj2); urx = obj2.getNum(); obj2.free(); obj1.arrayGet(5, &obj2); ury = obj2.getNum(); obj2.free(); obj1.arrayGet(6, &obj2); lrx = obj2.getNum(); obj2.free(); obj1.arrayGet(7, &obj2); lry = obj2.getNum(); obj2.free(); opiTransform(state, llx, lly, &tllx, &tlly); opiTransform(state, ulx, uly, &tulx, &tuly); opiTransform(state, urx, ury, &turx, &tury); opiTransform(state, lrx, lry, &tlrx, &tlry); writePSFmt("%ALDImagePosition: {0:.4g} {1:.4g} {2:.4g} {3:.4g} {4:.4g} {5:.4g} {6:.4g} {7:.4g}\n", tllx, tlly, tulx, tuly, turx, tury, tlrx, tlry); obj2.free(); } obj1.free(); dict->lookup("Resolution", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { obj1.arrayGet(0, &obj2); horiz = obj2.getNum(); obj2.free(); obj1.arrayGet(1, &obj2); vert = obj2.getNum(); obj2.free(); writePSFmt("%ALDImageResoution: {0:.4g} {1:.4g}\n", horiz, vert); obj2.free(); } obj1.free(); dict->lookup("Size", &obj1); if (obj1.isArray() && obj1.arrayGetLength() == 2) { obj1.arrayGet(0, &obj2); width = obj2.getInt(); obj2.free(); obj1.arrayGet(1, &obj2); height = obj2.getInt(); obj2.free(); writePSFmt("%ALDImageDimensions: {0:d} {1:d}\n", width, height); } obj1.free(); //~ ignoring 'Tags' entry //~ need to use writePSString() and deal with >255-char lines dict->lookup("Tint", &obj1); if (obj1.isNum()) { writePSFmt("%ALDImageTint: {0:.4g}\n", obj1.getNum()); } obj1.free(); dict->lookup("Transparency", &obj1); if (obj1.isBool()) { writePSFmt("%ALDImageTransparency: {0:s}\n", obj1.getBool() ? "true" : "false"); } obj1.free(); writePS("%%BeginObject: image\n"); writePS("opiMatrix2 setmatrix\n"); ++opi13Nest; } // Convert PDF user space coordinates to PostScript default user space // coordinates. This has to account for both the PDF CTM and the // PSOutputDev page-fitting transform. void PSOutputDev::opiTransform(GfxState *state, double x0, double y0, double *x1, double *y1) { double t; state->transform(x0, y0, x1, y1); *x1 += tx; *y1 += ty; if (rotate == 90) { t = *x1; *x1 = -*y1; *y1 = t; } else if (rotate == 180) { *x1 = -*x1; *y1 = -*y1; } else if (rotate == 270) { t = *x1; *x1 = *y1; *y1 = -t; } *x1 *= xScale; *y1 *= yScale; } void PSOutputDev::opiEnd(GfxState *state, Dict *opiDict) { Object dict; if (globalParams->getPSOPI()) { opiDict->lookup("2.0", &dict); if (dict.isDict()) { writePS("%%EndIncludedImage\n"); writePS("%%EndOPI\n"); writePS("grestore\n"); --opi20Nest; dict.free(); } else { dict.free(); opiDict->lookup("1.3", &dict); if (dict.isDict()) { writePS("%%EndObject\n"); writePS("restore\n"); --opi13Nest; } dict.free(); } } } GBool PSOutputDev::getFileSpec(Object *fileSpec, Object *fileName) { if (fileSpec->isString()) { fileSpec->copy(fileName); return gTrue; } if (fileSpec->isDict()) { fileSpec->dictLookup("DOS", fileName); if (fileName->isString()) { return gTrue; } fileName->free(); fileSpec->dictLookup("Mac", fileName); if (fileName->isString()) { return gTrue; } fileName->free(); fileSpec->dictLookup("Unix", fileName); if (fileName->isString()) { return gTrue; } fileName->free(); fileSpec->dictLookup("F", fileName); if (fileName->isString()) { return gTrue; } fileName->free(); } return gFalse; } #endif // OPI_SUPPORT void PSOutputDev::type3D0(GfxState *state, double wx, double wy) { writePSFmt("{0:.6g} {1:.6g} setcharwidth\n", wx, wy); writePS("q\n"); t3NeedsRestore = gTrue; } void PSOutputDev::type3D1(GfxState *state, double wx, double wy, double llx, double lly, double urx, double ury) { t3WX = wx; t3WY = wy; t3LLX = llx; t3LLY = lly; t3URX = urx; t3URY = ury; t3String = new GString(); writePS("q\n"); t3FillColorOnly = gTrue; t3Cacheable = gTrue; t3NeedsRestore = gTrue; } void PSOutputDev::drawForm(Ref id) { writePSFmt("f_{0:d}_{1:d}\n", id.num, id.gen); } void PSOutputDev::psXObject(Stream *psStream, Stream *level1Stream) { Stream *str; int c; if ((level == psLevel1 || level == psLevel1Sep) && level1Stream) { str = level1Stream; } else { str = psStream; } str->reset(); while ((c = str->getChar()) != EOF) { writePSChar(c); } str->close(); } //~ can nextFunc be reset to 0 -- maybe at the start of each page? //~ or maybe at the start of each color space / pattern? void PSOutputDev::cvtFunction(Function *func) { SampledFunction *func0; ExponentialFunction *func2; StitchingFunction *func3; PostScriptFunction *func4; int thisFunc, m, n, nSamples, i, j, k; switch (func->getType()) { case -1: // identity writePS("{}\n"); break; case 0: // sampled func0 = (SampledFunction *)func; thisFunc = nextFunc++; m = func0->getInputSize(); n = func0->getOutputSize(); nSamples = n; for (i = 0; i < m; ++i) { nSamples *= func0->getSampleSize(i); } writePSFmt("/xpdfSamples{0:d} [\n", thisFunc); for (i = 0; i < nSamples; ++i) { writePSFmt("{0:.6g}\n", func0->getSamples()[i]); } writePS("] def\n"); writePSFmt("{{ {0:d} array {1:d} array {2:d} 2 roll\n", 2*m, m, m+2); // [e01] [efrac] x0 x1 ... xm-1 for (i = m-1; i >= 0; --i) { // [e01] [efrac] x0 x1 ... xi writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add\n", func0->getDomainMin(i), (func0->getEncodeMax(i) - func0->getEncodeMin(i)) / (func0->getDomainMax(i) - func0->getDomainMin(i)), func0->getEncodeMin(i)); // [e01] [efrac] x0 x1 ... xi-1 xi' writePSFmt("dup 0 lt {{ pop 0 }} {{ dup {0:d} gt {{ pop {1:d} }} if }} ifelse\n", func0->getSampleSize(i) - 1, func0->getSampleSize(i) - 1); // [e01] [efrac] x0 x1 ... xi-1 xi' writePS("dup floor cvi exch dup ceiling cvi exch 2 index sub\n"); // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') xi'-floor(xi') writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, i); // [e01] [efrac] x0 x1 ... xi-1 floor(xi') ceiling(xi') writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+3, 2*i+1); // [e01] [efrac] x0 x1 ... xi-1 floor(xi') writePSFmt("{0:d} index {1:d} 3 2 roll put\n", i+2, 2*i); // [e01] [efrac] x0 x1 ... xi-1 } // [e01] [efrac] for (i = 0; i < n; ++i) { // [e01] [efrac] y(0) ... y(i-1) for (j = 0; j < (1<> k) & 1)); for (k = m - 2; k >= 0; --k) { writePSFmt("{0:d} mul {1:d} index {2:d} get add\n", func0->getSampleSize(k), i + j + 3, 2 * k + ((j >> k) & 1)); } if (n > 1) { writePSFmt("{0:d} mul {1:d} add ", n, i); } writePS("get\n"); } // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^m-1) for (j = 0; j < m; ++j) { // [e01] [efrac] y(0) ... y(i-1) s(0) s(1) ... s(2^(m-j)-1) for (k = 0; k < (1 << (m - j)); k += 2) { // [e01] [efrac] y(0) ... y(i-1) <2^(m-j)-k s values> writePSFmt("{0:d} index {1:d} get dup\n", i + k/2 + (1 << (m-j)) - k, j); writePS("3 2 roll mul exch 1 exch sub 3 2 roll mul add\n"); writePSFmt("{0:d} 1 roll\n", k/2 + (1 << (m-j)) - k - 1); } // [e01] [efrac] s'(0) s'(1) ... s(2^(m-j-1)-1) } // [e01] [efrac] y(0) ... y(i-1) s writePSFmt("{0:.6g} mul {1:.6g} add\n", func0->getDecodeMax(i) - func0->getDecodeMin(i), func0->getDecodeMin(i)); writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n", func0->getRangeMin(i), func0->getRangeMin(i), func0->getRangeMax(i), func0->getRangeMax(i)); // [e01] [efrac] y(0) ... y(i-1) y(i) } // [e01] [efrac] y(0) ... y(n-1) writePSFmt("{0:d} {1:d} roll pop pop }}\n", n+2, n); break; case 2: // exponential func2 = (ExponentialFunction *)func; n = func2->getOutputSize(); writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n", func2->getDomainMin(0), func2->getDomainMin(0), func2->getDomainMax(0), func2->getDomainMax(0)); // x for (i = 0; i < n; ++i) { // x y(0) .. y(i-1) writePSFmt("{0:d} index {1:.6g} exp {2:.6g} mul {3:.6g} add\n", i, func2->getE(), func2->getC1()[i] - func2->getC0()[i], func2->getC0()[i]); if (func2->getHasRange()) { writePSFmt("dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n", func2->getRangeMin(i), func2->getRangeMin(i), func2->getRangeMax(i), func2->getRangeMax(i)); } } // x y(0) .. y(n-1) writePSFmt("{0:d} {1:d} roll pop }}\n", n+1, n); break; case 3: // stitching func3 = (StitchingFunction *)func; thisFunc = nextFunc++; for (i = 0; i < func3->getNumFuncs(); ++i) { cvtFunction(func3->getFunc(i)); writePSFmt("/xpdfFunc{0:d}_{1:d} exch def\n", thisFunc, i); } writePSFmt("{{ dup {0:.6g} lt {{ pop {1:.6g} }} {{ dup {2:.6g} gt {{ pop {3:.6g} }} if }} ifelse\n", func3->getDomainMin(0), func3->getDomainMin(0), func3->getDomainMax(0), func3->getDomainMax(0)); for (i = 0; i < func3->getNumFuncs() - 1; ++i) { writePSFmt("dup {0:.6g} lt {{ {1:.6g} sub {2:.6g} mul {3:.6g} add xpdfFunc{4:d}_{5:d} }} {{\n", func3->getBounds()[i+1], func3->getBounds()[i], func3->getScale()[i], func3->getEncode()[2*i], thisFunc, i); } writePSFmt("{0:.6g} sub {1:.6g} mul {2:.6g} add xpdfFunc{3:d}_{4:d}\n", func3->getBounds()[i], func3->getScale()[i], func3->getEncode()[2*i], thisFunc, i); for (i = 0; i < func3->getNumFuncs() - 1; ++i) { writePS("} ifelse\n"); } writePS("}\n"); break; case 4: // PostScript func4 = (PostScriptFunction *)func; writePS(func4->getCodeString()->getCString()); writePS("\n"); break; } } void PSOutputDev::writePSChar(char c) { if (t3String) { t3String->append(c); } else { (*outputFunc)(outputStream, &c, 1); } } void PSOutputDev::writePS(const char *s) { if (t3String) { t3String->append(s); } else { (*outputFunc)(outputStream, s, (int)strlen(s)); } } void PSOutputDev::writePSFmt(const char *fmt, ...) { va_list args; GString *buf; va_start(args, fmt); if (t3String) { t3String->appendfv((char *)fmt, args); } else { buf = GString::formatv((char *)fmt, args); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } va_end(args); } void PSOutputDev::writePSString(GString *s) { Guchar *p; int n, line; char buf[8]; writePSChar('('); line = 1; for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) { if (line >= 64) { writePSChar('\\'); writePSChar('\n'); line = 0; } if (*p == '(' || *p == ')' || *p == '\\') { writePSChar('\\'); writePSChar((char)*p); line += 2; } else if (*p < 0x20 || *p >= 0x80) { sprintf(buf, "\\%03o", *p); writePS(buf); line += 4; } else { writePSChar((char)*p); ++line; } } writePSChar(')'); } void PSOutputDev::writePSName(const char *s) { const char *p; char c; p = s; while ((c = *p++)) { if (c <= (char)0x20 || c >= (char)0x7f || c == '(' || c == ')' || c == '<' || c == '>' || c == '[' || c == ']' || c == '{' || c == '}' || c == '/' || c == '%') { writePSFmt("#{0:02x}", c & 0xff); } else { writePSChar(c); } } } GString *PSOutputDev::filterPSName(GString *name) { GString *name2; char buf[8]; int i; char c; name2 = new GString(); // ghostscript chokes on names that begin with out-of-limits // numbers, e.g., 1e4foo is handled correctly (as a name), but // 1e999foo generates a limitcheck error c = name->getChar(0); if (c >= '0' && c <= '9') { name2->append('f'); } for (i = 0; i < name->getLength(); ++i) { c = name->getChar(i); if (c <= (char)0x20 || c >= (char)0x7f || c == '(' || c == ')' || c == '<' || c == '>' || c == '[' || c == ']' || c == '{' || c == '}' || c == '/' || c == '%') { sprintf(buf, "#%02x", c & 0xff); name2->append(buf); } else { name2->append(c); } } return name2; } // Write a DSC-compliant . void PSOutputDev::writePSTextLine(GString *s) { int i, j, step; int c; // - DSC comments must be printable ASCII; control chars and // backslashes have to be escaped (we do cheap Unicode-to-ASCII // conversion by simply ignoring the high byte) // - lines are limited to 255 chars (we limit to 200 here to allow // for the keyword, which was emitted by the caller) // - lines that start with a left paren are treated as // instead of , so we escape a leading paren if (s->getLength() >= 2 && (s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { i = 3; step = 2; } else { i = 0; step = 1; } for (j = 0; i < s->getLength() && j < 200; i += step) { c = s->getChar(i) & 0xff; if (c == '\\') { writePS("\\\\"); j += 2; } else if (c < 0x20 || c > 0x7e || (j == 0 && c == '(')) { writePSFmt("\\{0:03o}", c); j += 4; } else { writePSChar(c); ++j; } } writePS("\n"); } xpdf-3.03/xpdf/UnicodeTypeTable.h0000644000076400007640000000077411622305345016235 0ustar dereknderekn//======================================================================== // // UnicodeTypeTable.h // // Copyright 2003 Glyph & Cog, LLC // //======================================================================== #ifndef UNICODETYPETABLE_H #define UNICODETYPETABLE_H #include "gtypes.h" extern GBool unicodeTypeL(Unicode c); extern GBool unicodeTypeR(Unicode c); extern GBool unicodeTypeNum(Unicode c); extern GBool unicodeTypeAlphaNum(Unicode c); extern Unicode unicodeToUpper(Unicode c); #endif xpdf-3.03/xpdf/XPDFViewer.cc0000644000076400007640000032746011622305345015122 0ustar dereknderekn//======================================================================== // // XPDFViewer.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #ifdef HAVE_X11_XPM_H #include #endif #if defined(__sgi) && (XmVERSION <= 1) #define Object XtObject #include #undef Object #endif #include "gmem.h" #include "gfile.h" #include "GString.h" #include "GList.h" #include "Error.h" #include "GlobalParams.h" #include "PDFDoc.h" #include "Link.h" #include "ErrorCodes.h" #include "Outline.h" #include "UnicodeMap.h" #ifndef DISABLE_OUTLINE #define Object XtObject #include "XPDFTree.h" #undef Object #endif #include "XPDFApp.h" #include "XPDFViewer.h" #include "PSOutputDev.h" #include "config.h" // these macro defns conflict with xpdf's Object class #ifdef LESSTIF_VERSION #undef XtDisplay #undef XtScreen #undef XtWindow #undef XtParent #undef XtIsRealized #endif #if XmVERSION <= 1 #define XmSET True #define XmUNSET False #endif // hack around old X includes which are missing these symbols #ifndef XK_Page_Up #define XK_Page_Up 0xFF55 #endif #ifndef XK_Page_Down #define XK_Page_Down 0xFF56 #endif #ifndef XK_KP_Home #define XK_KP_Home 0xFF95 #endif #ifndef XK_KP_Left #define XK_KP_Left 0xFF96 #endif #ifndef XK_KP_Up #define XK_KP_Up 0xFF97 #endif #ifndef XK_KP_Right #define XK_KP_Right 0xFF98 #endif #ifndef XK_KP_Down #define XK_KP_Down 0xFF99 #endif #ifndef XK_KP_Prior #define XK_KP_Prior 0xFF9A #endif #ifndef XK_KP_Page_Up #define XK_KP_Page_Up 0xFF9A #endif #ifndef XK_KP_Next #define XK_KP_Next 0xFF9B #endif #ifndef XK_KP_Page_Down #define XK_KP_Page_Down 0xFF9B #endif #ifndef XK_KP_End #define XK_KP_End 0xFF9C #endif #ifndef XK_KP_Begin #define XK_KP_Begin 0xFF9D #endif #ifndef XK_KP_Insert #define XK_KP_Insert 0xFF9E #endif #ifndef XK_KP_Delete #define XK_KP_Delete 0xFF9F #endif //------------------------------------------------------------------------ // GUI includes //------------------------------------------------------------------------ #include "xpdfIcon.xpm" #include "leftArrow.xbm" #include "leftArrowDis.xbm" #include "dblLeftArrow.xbm" #include "dblLeftArrowDis.xbm" #include "rightArrow.xbm" #include "rightArrowDis.xbm" #include "dblRightArrow.xbm" #include "dblRightArrowDis.xbm" #include "backArrow.xbm" #include "backArrowDis.xbm" #include "forwardArrow.xbm" #include "forwardArrowDis.xbm" #include "find.xbm" #include "findDis.xbm" #include "print.xbm" #include "printDis.xbm" #include "about.xbm" #include "about-text.h" //------------------------------------------------------------------------ struct ZoomMenuInfo { const char *label; double zoom; }; static ZoomMenuInfo zoomMenuInfo[nZoomMenuItems] = { { "400%", 400 }, { "200%", 200 }, { "150%", 150 }, { "125%", 125 }, { "100%", 100 }, { "50%", 50 }, { "25%", 25 }, { "12.5%", 12.5 }, { "fit page", zoomPage }, { "fit width", zoomWidth } }; #define maxZoomIdx 0 #define defZoomIdx 3 #define minZoomIdx 7 #define zoomPageIdx 8 #define zoomWidthIdx 9 //------------------------------------------------------------------------ #define cmdMaxArgs 8 XPDFViewerCmd XPDFViewer::cmdTab[] = { { "about", 0, gFalse, gFalse, &XPDFViewer::cmdAbout }, { "closeOutline", 0, gFalse, gFalse, &XPDFViewer::cmdCloseOutline }, { "closeWindow", 0, gFalse, gFalse, &XPDFViewer::cmdCloseWindow }, { "continuousMode", 0, gFalse, gFalse, &XPDFViewer::cmdContinuousMode }, { "endPan", 0, gTrue, gTrue, &XPDFViewer::cmdEndPan }, { "endSelection", 0, gTrue, gTrue, &XPDFViewer::cmdEndSelection }, { "find", 0, gTrue, gFalse, &XPDFViewer::cmdFind }, { "findNext", 0, gTrue, gFalse, &XPDFViewer::cmdFindNext }, { "focusToDocWin", 0, gFalse, gFalse, &XPDFViewer::cmdFocusToDocWin }, { "focusToPageNum", 0, gFalse, gFalse, &XPDFViewer::cmdFocusToPageNum }, { "followLink", 0, gTrue, gTrue, &XPDFViewer::cmdFollowLink }, { "followLinkInNewWin", 0, gTrue, gTrue, &XPDFViewer::cmdFollowLinkInNewWin }, { "followLinkInNewWinNoSel", 0, gTrue, gTrue, &XPDFViewer::cmdFollowLinkInNewWinNoSel }, { "followLinkNoSel", 0, gTrue, gTrue, &XPDFViewer::cmdFollowLinkNoSel }, { "fullScreenMode", 0, gFalse, gFalse, &XPDFViewer::cmdFullScreenMode }, { "goBackward", 0, gFalse, gFalse, &XPDFViewer::cmdGoBackward }, { "goForward", 0, gFalse, gFalse, &XPDFViewer::cmdGoForward }, { "gotoDest", 1, gTrue, gFalse, &XPDFViewer::cmdGotoDest }, { "gotoLastPage", 0, gTrue, gFalse, &XPDFViewer::cmdGotoLastPage }, { "gotoLastPageNoScroll", 0, gTrue, gFalse, &XPDFViewer::cmdGotoLastPageNoScroll }, { "gotoPage", 1, gTrue, gFalse, &XPDFViewer::cmdGotoPage }, { "gotoPageNoScroll", 1, gTrue, gFalse, &XPDFViewer::cmdGotoPageNoScroll }, { "nextPage", 0, gTrue, gFalse, &XPDFViewer::cmdNextPage }, { "nextPageNoScroll", 0, gTrue, gFalse, &XPDFViewer::cmdNextPageNoScroll }, { "open", 0, gFalse, gFalse, &XPDFViewer::cmdOpen }, { "openFile", 1, gFalse, gFalse, &XPDFViewer::cmdOpenFile }, { "openFileAtDest", 2, gFalse, gFalse, &XPDFViewer::cmdOpenFileAtDest }, { "openFileAtDestInNewWin", 2, gFalse, gFalse, &XPDFViewer::cmdOpenFileAtDestInNewWin }, { "openFileAtPage", 2, gFalse, gFalse, &XPDFViewer::cmdOpenFileAtPage }, { "openFileAtPageInNewWin", 2, gFalse, gFalse, &XPDFViewer::cmdOpenFileAtPageInNewWin }, { "openFileInNewWin", 1, gFalse, gFalse, &XPDFViewer::cmdOpenFileInNewWin }, { "openInNewWin", 0, gFalse, gFalse, &XPDFViewer::cmdOpenInNewWin }, { "openOutline", 0, gFalse, gFalse, &XPDFViewer::cmdOpenOutline }, { "pageDown", 0, gTrue, gFalse, &XPDFViewer::cmdPageDown }, { "pageUp", 0, gTrue, gFalse, &XPDFViewer::cmdPageUp }, { "postPopupMenu", 0, gFalse, gTrue, &XPDFViewer::cmdPostPopupMenu }, { "prevPage", 0, gTrue, gFalse, &XPDFViewer::cmdPrevPage }, { "prevPageNoScroll", 0, gTrue, gFalse, &XPDFViewer::cmdPrevPageNoScroll }, { "print", 0, gTrue, gFalse, &XPDFViewer::cmdPrint }, { "quit", 0, gFalse, gFalse, &XPDFViewer::cmdQuit }, { "raise", 0, gFalse, gFalse, &XPDFViewer::cmdRaise }, { "redraw", 0, gTrue, gFalse, &XPDFViewer::cmdRedraw }, { "reload", 0, gTrue, gFalse, &XPDFViewer::cmdReload }, { "rotateCCW", 0, gTrue, gFalse, &XPDFViewer::cmdRotateCCW }, { "rotateCW", 0, gTrue, gFalse, &XPDFViewer::cmdRotateCW }, { "run", 1, gFalse, gFalse, &XPDFViewer::cmdRun }, { "scrollDown", 1, gTrue, gFalse, &XPDFViewer::cmdScrollDown }, { "scrollDownNextPage", 1, gTrue, gFalse, &XPDFViewer::cmdScrollDownNextPage }, { "scrollLeft", 1, gTrue, gFalse, &XPDFViewer::cmdScrollLeft }, { "scrollOutlineDown", 1, gTrue, gFalse, &XPDFViewer::cmdScrollOutlineDown }, { "scrollOutlineUp", 1, gTrue, gFalse, &XPDFViewer::cmdScrollOutlineUp }, { "scrollRight", 1, gTrue, gFalse, &XPDFViewer::cmdScrollRight }, { "scrollToBottomEdge", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToBottomEdge }, { "scrollToBottomRight", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToBottomRight }, { "scrollToLeftEdge", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToLeftEdge }, { "scrollToRightEdge", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToRightEdge }, { "scrollToTopEdge", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToTopEdge }, { "scrollToTopLeft", 0, gTrue, gFalse, &XPDFViewer::cmdScrollToTopLeft }, { "scrollUp", 1, gTrue, gFalse, &XPDFViewer::cmdScrollUp }, { "scrollUpPrevPage", 1, gTrue, gFalse, &XPDFViewer::cmdScrollUpPrevPage }, { "setSelection", 5, gTrue, gFalse, &XPDFViewer::cmdSetSelection }, { "singlePageMode", 0, gFalse, gFalse, &XPDFViewer::cmdSinglePageMode }, { "startPan", 0, gTrue, gTrue, &XPDFViewer::cmdStartPan }, { "startSelection", 0, gTrue, gTrue, &XPDFViewer::cmdStartSelection }, { "toggleContinuousMode", 0, gFalse, gFalse, &XPDFViewer::cmdToggleContinuousMode }, { "toggleFullScreenMode", 0, gFalse, gFalse, &XPDFViewer::cmdToggleFullScreenMode }, { "toggleOutline", 0, gFalse, gFalse, &XPDFViewer::cmdToggleOutline }, { "windowMode", 0, gFalse, gFalse, &XPDFViewer::cmdWindowMode }, { "zoomFitPage", 0, gFalse, gFalse, &XPDFViewer::cmdZoomFitPage }, { "zoomFitWidth", 0, gFalse, gFalse, &XPDFViewer::cmdZoomFitWidth }, { "zoomIn", 0, gFalse, gFalse, &XPDFViewer::cmdZoomIn }, { "zoomOut", 0, gFalse, gFalse, &XPDFViewer::cmdZoomOut }, { "zoomPercent", 1, gFalse, gFalse, &XPDFViewer::cmdZoomPercent }, { "zoomToSelection", 0, gTrue, gFalse, &XPDFViewer::cmdZoomToSelection } }; #define nCmds (sizeof(cmdTab) / sizeof(XPDFViewerCmd)) //------------------------------------------------------------------------ XPDFViewer::XPDFViewer(XPDFApp *appA, GString *fileName, int pageA, GString *destName, GBool fullScreen, GString *ownerPassword, GString *userPassword) { LinkDest *dest; int pg; double z; app = appA; win = NULL; core = NULL; ok = gFalse; #ifndef DISABLE_OUTLINE outlineLabels = NULL; outlineLabelsLength = outlineLabelsSize = 0; outlinePaneWidth = 175; #endif // do Motif-specific initialization and create the window; // this also creates the core object initWindow(fullScreen); initAboutDialog(); initFindDialog(); initPrintDialog(); openDialog = NULL; saveAsDialog = NULL; dest = NULL; // make gcc happy pg = pageA; // make gcc happy if (fileName) { if (loadFile(fileName, ownerPassword, userPassword)) { getPageAndDest(pageA, destName, &pg, &dest); #ifndef DISABLE_OUTLINE if (outlineScroll != None && core->getDoc()->getOutline()->getItems() && core->getDoc()->getOutline()->getItems()->getLength() > 0) { XtVaSetValues(outlineScroll, XmNwidth, outlinePaneWidth, NULL); } #endif } else { return; } } core->resizeToPage(pg); // map the window -- we do this after calling resizeToPage to avoid // an annoying on-screen resize mapWindow(); // display the first page z = core->getZoom(); if (dest) { displayDest(dest, z, core->getRotate(), gTrue); delete dest; } else { displayPage(pg, z, core->getRotate(), gTrue, gTrue); } ok = gTrue; } XPDFViewer::XPDFViewer(XPDFApp *appA, PDFDoc *doc, int pageA, GString *destName, GBool fullScreen) { LinkDest *dest; int pg; double z; app = appA; win = NULL; core = NULL; ok = gFalse; #ifndef DISABLE_OUTLINE outlineLabels = NULL; outlineLabelsLength = outlineLabelsSize = 0; outlinePaneWidth = 175; #endif // do Motif-specific initialization and create the window; // this also creates the core object initWindow(fullScreen); initAboutDialog(); initFindDialog(); initPrintDialog(); openDialog = NULL; saveAsDialog = NULL; dest = NULL; // make gcc happy pg = pageA; // make gcc happy if (doc) { core->loadDoc(doc); getPageAndDest(pageA, destName, &pg, &dest); #ifndef DISABLE_OUTLINE if (outlineScroll != None && core->getDoc()->getOutline()->getItems() && core->getDoc()->getOutline()->getItems()->getLength() > 0) { XtVaSetValues(outlineScroll, XmNwidth, outlinePaneWidth, NULL); } #endif } core->resizeToPage(pg); // map the window -- we do this after calling resizeToPage to avoid // an annoying on-screen resize mapWindow(); // display the first page z = core->getZoom(); if (dest) { displayDest(dest, z, core->getRotate(), gTrue); delete dest; } else { displayPage(pg, z, core->getRotate(), gTrue, gTrue); } ok = gTrue; } XPDFViewer::~XPDFViewer() { delete core; if (aboutBigFont) { XmFontListFree(aboutBigFont); } if (aboutVersionFont) { XmFontListFree(aboutVersionFont); } if (aboutFixedFont) { XmFontListFree(aboutFixedFont); } closeWindow(); #ifndef DISABLE_OUTLINE if (outlineLabels) { gfree(outlineLabels); } #endif } void XPDFViewer::open(GString *fileName, int pageA, GString *destName) { LinkDest *dest; int pg; double z; if (!core->getDoc() || fileName->cmp(core->getDoc()->getFileName())) { if (!loadFile(fileName, NULL, NULL)) { return; } } getPageAndDest(pageA, destName, &pg, &dest); z = core->getZoom(); if (dest) { displayDest(dest, z, core->getRotate(), gTrue); delete dest; } else { displayPage(pg, z, core->getRotate(), gTrue, gTrue); } } void XPDFViewer::clear() { char *title; XmString s; core->clear(); // set up title title = app->getTitle() ? app->getTitle()->getCString() : (char *)xpdfAppName; XtVaSetValues(win, XmNtitle, title, XmNiconName, title, NULL); if (toolBar != None) { // set up number-of-pages display s = XmStringCreateLocalized(""); XtVaSetValues(pageNumText, XmNlabelString, s, NULL); XmStringFree(s); s = XmStringCreateLocalized(" of 0"); XtVaSetValues(pageCountLabel, XmNlabelString, s, NULL); XmStringFree(s); // disable buttons XtVaSetValues(prevTenPageBtn, XmNsensitive, False, NULL); XtVaSetValues(prevPageBtn, XmNsensitive, False, NULL); XtVaSetValues(nextTenPageBtn, XmNsensitive, False, NULL); XtVaSetValues(nextPageBtn, XmNsensitive, False, NULL); } // remove the old outline #ifndef DISABLE_OUTLINE setupOutline(); #endif } //------------------------------------------------------------------------ // load / display //------------------------------------------------------------------------ GBool XPDFViewer::loadFile(GString *fileName, GString *ownerPassword, GString *userPassword) { return core->loadFile(fileName, ownerPassword, userPassword) == errNone; } void XPDFViewer::reloadFile() { int pg; if (!core->getDoc()) { return; } pg = core->getPageNum(); loadFile(core->getDoc()->getFileName()); if (pg > core->getDoc()->getNumPages()) { pg = core->getDoc()->getNumPages(); } displayPage(pg, core->getZoom(), core->getRotate(), gFalse, gFalse); } void XPDFViewer::displayPage(int pageA, double zoomA, int rotateA, GBool scrollToTop, GBool addToHist) { core->displayPage(pageA, zoomA, rotateA, scrollToTop, addToHist); } void XPDFViewer::displayDest(LinkDest *dest, double zoomA, int rotateA, GBool addToHist) { core->displayDest(dest, zoomA, rotateA, addToHist); } void XPDFViewer::getPageAndDest(int pageA, GString *destName, int *pageOut, LinkDest **destOut) { Ref pageRef; // find the page number for a named destination *pageOut = pageA; *destOut = NULL; if (destName && (*destOut = core->getDoc()->findDest(destName))) { if ((*destOut)->isPageRef()) { pageRef = (*destOut)->getPageRef(); *pageOut = core->getDoc()->findPage(pageRef.num, pageRef.gen); } else { *pageOut = (*destOut)->getPageNum(); } } if (*pageOut <= 0) { *pageOut = 1; } if (*pageOut > core->getDoc()->getNumPages()) { *pageOut = core->getDoc()->getNumPages(); } } //------------------------------------------------------------------------ // hyperlinks / actions //------------------------------------------------------------------------ void XPDFViewer::doLink(int wx, int wy, GBool onlyIfNoSelection, GBool newWin) { XPDFViewer *newViewer; LinkAction *action; int pg, selPg; double xu, yu, selULX, selULY, selLRX, selLRY; if (core->getHyperlinksEnabled() && core->cvtWindowToUser(wx, wy, &pg, &xu, &yu) && !(onlyIfNoSelection && core->getSelection(&selPg, &selULX, &selULY, &selLRX, &selLRY))) { if ((action = core->findLink(pg, xu, yu))) { if (newWin && core->getDoc()->getFileName() && (action->getKind() == actionGoTo || action->getKind() == actionGoToR || (action->getKind() == actionNamed && ((LinkNamed *)action)->getName()->cmp("Quit")))) { newViewer = app->open(core->getDoc()->getFileName()); newViewer->core->doAction(action); } else { core->doAction(action); } } } } void XPDFViewer::actionCbk(void *data, char *action) { XPDFViewer *viewer = (XPDFViewer *)data; if (!strcmp(action, "Quit")) { viewer->app->quit(); } } //------------------------------------------------------------------------ // keyboard/mouse input //------------------------------------------------------------------------ void XPDFViewer::keyPressCbk(void *data, KeySym key, Guint modifiers, XEvent *event) { XPDFViewer *viewer = (XPDFViewer *)data; int keyCode; GList *cmds; int i; if (key >= 0x20 && key <= 0xfe) { keyCode = (int)key; } else if (key == XK_Tab || key == XK_KP_Tab) { keyCode = xpdfKeyCodeTab; } else if (key == XK_Return) { keyCode = xpdfKeyCodeReturn; } else if (key == XK_KP_Enter) { keyCode = xpdfKeyCodeEnter; } else if (key == XK_BackSpace) { keyCode = xpdfKeyCodeBackspace; } else if (key == XK_Insert || key == XK_KP_Insert) { keyCode = xpdfKeyCodeInsert; } else if (key == XK_Delete || key == XK_KP_Delete) { keyCode = xpdfKeyCodeDelete; } else if (key == XK_Home || key == XK_KP_Home) { keyCode = xpdfKeyCodeHome; } else if (key == XK_End || key == XK_KP_End) { keyCode = xpdfKeyCodeEnd; } else if (key == XK_Page_Up || key == XK_KP_Page_Up) { keyCode = xpdfKeyCodePgUp; } else if (key == XK_Page_Down || key == XK_KP_Page_Down) { keyCode = xpdfKeyCodePgDn; } else if (key == XK_Left || key == XK_KP_Left) { keyCode = xpdfKeyCodeLeft; } else if (key == XK_Right || key == XK_KP_Right) { keyCode = xpdfKeyCodeRight; } else if (key == XK_Up || key == XK_KP_Up) { keyCode = xpdfKeyCodeUp; } else if (key == XK_Down || key == XK_KP_Down) { keyCode = xpdfKeyCodeDown; } else if (key >= XK_F1 && key <= XK_F35) { keyCode = xpdfKeyCodeF1 + (key - XK_F1); } else { return; } if ((cmds = globalParams->getKeyBinding(keyCode, viewer->getModifiers(modifiers), viewer->getContext(modifiers)))) { for (i = 0; i < cmds->getLength(); ++i) { viewer->execCmd((GString *)cmds->get(i), event); } deleteGList(cmds, GString); } } void XPDFViewer::mouseCbk(void *data, XEvent *event) { XPDFViewer *viewer = (XPDFViewer *)data; int keyCode; GList *cmds; int i; if (event->type == ButtonPress) { if (event->xbutton.button >= 1 && event->xbutton.button <= 32) { keyCode = xpdfKeyCodeMousePress1 + event->xbutton.button - 1; } else { return; } } else if (event->type == ButtonRelease) { if (event->xbutton.button >= 1 && event->xbutton.button <= 32) { keyCode = xpdfKeyCodeMouseRelease1 + event->xbutton.button - 1; } else { return; } } else { return; } if ((cmds = globalParams->getKeyBinding(keyCode, viewer->getModifiers( event->xkey.state), viewer->getContext( event->xkey.state)))) { for (i = 0; i < cmds->getLength(); ++i) { viewer->execCmd((GString *)cmds->get(i), event); } deleteGList(cmds, GString); } } int XPDFViewer::getModifiers(Guint modifiers) { int mods; mods = 0; if (modifiers & ShiftMask) { mods |= xpdfKeyModShift; } if (modifiers & ControlMask) { mods |= xpdfKeyModCtrl; } if (modifiers & Mod1Mask) { mods |= xpdfKeyModAlt; } return mods; } int XPDFViewer::getContext(Guint modifiers) { int context; context = (core->getFullScreen() ? xpdfKeyContextFullScreen : xpdfKeyContextWindow) | (core->getContinuousMode() ? xpdfKeyContextContinuous : xpdfKeyContextSinglePage) | (core->getLinkAction() ? xpdfKeyContextOverLink : xpdfKeyContextOffLink) | ((modifiers & Mod5Mask) ? xpdfKeyContextScrLockOn : xpdfKeyContextScrLockOff); return context; } void XPDFViewer::execCmd(GString *cmd, XEvent *event) { GString *name; GString *args[cmdMaxArgs]; char *p0, *p1; int nArgs, i; int a, b, m, cmp; //----- parse the command name = NULL; nArgs = 0; for (i = 0; i < cmdMaxArgs; ++i) { args[i] = NULL; } p0 = cmd->getCString(); for (p1 = p0; *p1 && isalnum(*p1); ++p1) ; if (p1 == p0) { goto err1; } name = new GString(p0, p1 - p0); if (*p1 == '(') { while (nArgs < cmdMaxArgs) { p0 = p1 + 1; for (p1 = p0; *p1 && *p1 != ',' && *p1 != ')'; ++p1) ; args[nArgs++] = new GString(p0, p1 - p0); if (*p1 != ',') { break; } } if (*p1 != ')') { goto err1; } ++p1; } if (*p1) { goto err1; } //----- find the command a = -1; b = nCmds; // invariant: cmdTab[a].name < name < cmdTab[b].name while (b - a > 1) { m = (a + b) / 2; cmp = strcmp(cmdTab[m].name, name->getCString()); if (cmp < 0) { a = m; } else if (cmp > 0) { b = m; } else { a = b = m; } } if (cmp != 0) { goto err1; } //----- execute the command if (nArgs != cmdTab[a].nArgs || (cmdTab[a].requiresEvent && !event)) { goto err1; } if (cmdTab[a].requiresDoc && !core->getDoc()) { // don't issue an error message for this -- it happens, e.g., when // clicking in a window with no open PDF file goto err2; } (this->*cmdTab[a].func)(args, nArgs, event); //----- clean up delete name; for (i = 0; i < nArgs; ++i) { if (args[i]) { delete args[i]; } } return; err1: error(errConfig, -1, "Invalid command syntax: '{0:t}'", cmd); err2: if (name) { delete name; } for (i = 0; i < nArgs; ++i) { if (args[i]) { delete args[i]; } } } //------------------------------------------------------------------------ // command functions //------------------------------------------------------------------------ static int mouseX(XEvent *event) { switch (event->type) { case ButtonPress: case ButtonRelease: return event->xbutton.x; case KeyPress: return event->xkey.x; } return 0; } static int mouseY(XEvent *event) { switch (event->type) { case ButtonPress: case ButtonRelease: return event->xbutton.y; case KeyPress: return event->xkey.y; } return 0; } void XPDFViewer::cmdAbout(GString *args[], int nArgs, XEvent *event) { XtManageChild(aboutDialog); } void XPDFViewer::cmdCloseOutline(GString *args[], int nArgs, XEvent *event) { #ifndef DISABLE_OUTLINE Dimension w; if (outlineScroll == None) { return; } XtVaGetValues(outlineScroll, XmNwidth, &w, NULL); if (w > 1) { outlinePaneWidth = w; // this ugly kludge is apparently the only way to resize the panes // within an XmPanedWindow XtVaSetValues(outlineScroll, XmNpaneMinimum, 1, XmNpaneMaximum, 1, NULL); XtVaSetValues(outlineScroll, XmNpaneMinimum, 1, XmNpaneMaximum, 10000, NULL); } #endif } void XPDFViewer::cmdCloseWindow(GString *args[], int nArgs, XEvent *event) { app->close(this, gFalse); } void XPDFViewer::cmdContinuousMode(GString *args[], int nArgs, XEvent *event) { Widget btn; if (core->getContinuousMode()) { return; } core->setContinuousMode(gTrue); btn = XtNameToWidget(popupMenu, "continuousMode"); XtVaSetValues(btn, XmNset, XmSET, NULL); } void XPDFViewer::cmdEndPan(GString *args[], int nArgs, XEvent *event) { core->endPan(mouseX(event), mouseY(event)); } void XPDFViewer::cmdEndSelection(GString *args[], int nArgs, XEvent *event) { core->endSelection(mouseX(event), mouseY(event)); } void XPDFViewer::cmdFind(GString *args[], int nArgs, XEvent *event) { mapFindDialog(); } void XPDFViewer::cmdFindNext(GString *args[], int nArgs, XEvent *event) { doFind(gTrue); } void XPDFViewer::cmdFocusToDocWin(GString *args[], int nArgs, XEvent *event) { core->takeFocus(); } void XPDFViewer::cmdFocusToPageNum(GString *args[], int nArgs, XEvent *event) { if (toolBar != None) { XmTextFieldSetSelection(pageNumText, 0, strlen(XmTextFieldGetString(pageNumText)), XtLastTimestampProcessed(display)); XmProcessTraversal(pageNumText, XmTRAVERSE_CURRENT); } } void XPDFViewer::cmdFollowLink(GString *args[], int nArgs, XEvent *event) { doLink(mouseX(event), mouseY(event), gFalse, gFalse); } void XPDFViewer::cmdFollowLinkInNewWin(GString *args[], int nArgs, XEvent *event) { doLink(mouseX(event), mouseY(event), gFalse, gTrue); } void XPDFViewer::cmdFollowLinkInNewWinNoSel(GString *args[], int nArgs, XEvent *event) { doLink(mouseX(event), mouseY(event), gTrue, gTrue); } void XPDFViewer::cmdFollowLinkNoSel(GString *args[], int nArgs, XEvent *event) { doLink(mouseX(event), mouseY(event), gTrue, gFalse); } void XPDFViewer::cmdFullScreenMode(GString *args[], int nArgs, XEvent *event) { PDFDoc *doc; XPDFViewer *viewer; int pg; Widget btn; if (core->getFullScreen()) { return; } pg = core->getPageNum(); XtPopdown(win); doc = core->takeDoc(gFalse); viewer = app->reopen(this, doc, pg, gTrue); btn = XtNameToWidget(viewer->popupMenu, "fullScreen"); XtVaSetValues(btn, XmNset, XmSET, NULL); } void XPDFViewer::cmdGoBackward(GString *args[], int nArgs, XEvent *event) { core->goBackward(); } void XPDFViewer::cmdGoForward(GString *args[], int nArgs, XEvent *event) { core->goForward(); } void XPDFViewer::cmdGotoDest(GString *args[], int nArgs, XEvent *event) { int pg; LinkDest *dest; getPageAndDest(1, args[0], &pg, &dest); if (dest) { displayDest(dest, core->getZoom(), core->getRotate(), gTrue); delete dest; } } void XPDFViewer::cmdGotoLastPage(GString *args[], int nArgs, XEvent *event) { displayPage(core->getDoc()->getNumPages(), core->getZoom(), core->getRotate(), gTrue, gTrue); } void XPDFViewer::cmdGotoLastPageNoScroll(GString *args[], int nArgs, XEvent *event) { displayPage(core->getDoc()->getNumPages(), core->getZoom(), core->getRotate(), gFalse, gTrue); } void XPDFViewer::cmdGotoPage(GString *args[], int nArgs, XEvent *event) { int pg; pg = atoi(args[0]->getCString()); if (pg < 1 || pg > core->getDoc()->getNumPages()) { return; } displayPage(pg, core->getZoom(), core->getRotate(), gTrue, gTrue); } void XPDFViewer::cmdGotoPageNoScroll(GString *args[], int nArgs, XEvent *event) { int pg; pg = atoi(args[0]->getCString()); if (pg < 1 || pg > core->getDoc()->getNumPages()) { return; } displayPage(pg, core->getZoom(), core->getRotate(), gFalse, gTrue); } void XPDFViewer::cmdNextPage(GString *args[], int nArgs, XEvent *event) { core->gotoNextPage(1, gTrue); } void XPDFViewer::cmdNextPageNoScroll(GString *args[], int nArgs, XEvent *event) { core->gotoNextPage(1, gFalse); } void XPDFViewer::cmdOpen(GString *args[], int nArgs, XEvent *event) { mapOpenDialog(gFalse); } void XPDFViewer::cmdOpenFile(GString *args[], int nArgs, XEvent *event) { open(args[0], 1, NULL); } void XPDFViewer::cmdOpenFileAtDest(GString *args[], int nArgs, XEvent *event) { open(args[0], 1, args[1]); } void XPDFViewer::cmdOpenFileAtDestInNewWin(GString *args[], int nArgs, XEvent *event) { app->openAtDest(args[0], args[1]); } void XPDFViewer::cmdOpenFileAtPage(GString *args[], int nArgs, XEvent *event) { open(args[0], atoi(args[1]->getCString()), NULL); } void XPDFViewer::cmdOpenFileAtPageInNewWin(GString *args[], int nArgs, XEvent *event) { app->open(args[0], atoi(args[1]->getCString())); } void XPDFViewer::cmdOpenFileInNewWin(GString *args[], int nArgs, XEvent *event) { app->open(args[0]); } void XPDFViewer::cmdOpenInNewWin(GString *args[], int nArgs, XEvent *event) { mapOpenDialog(gTrue); } void XPDFViewer::cmdOpenOutline(GString *args[], int nArgs, XEvent *event) { #ifndef DISABLE_OUTLINE Dimension w; if (outlineScroll == None) { return; } XtVaGetValues(outlineScroll, XmNwidth, &w, NULL); if (w == 1) { // this ugly kludge is apparently the only way to resize the panes // within an XmPanedWindow XtVaSetValues(outlineScroll, XmNpaneMinimum, outlinePaneWidth, XmNpaneMaximum, outlinePaneWidth, NULL); XtVaSetValues(outlineScroll, XmNpaneMinimum, 1, XmNpaneMaximum, 10000, NULL); } #endif } void XPDFViewer::cmdPageDown(GString *args[], int nArgs, XEvent *event) { core->scrollPageDown(); } void XPDFViewer::cmdPageUp(GString *args[], int nArgs, XEvent *event) { core->scrollPageUp(); } void XPDFViewer::cmdPostPopupMenu(GString *args[], int nArgs, XEvent *event) { XmMenuPosition(popupMenu, event->type == ButtonPress ? &event->xbutton : (XButtonEvent *)NULL); XtManageChild(popupMenu); // this is magic (taken from DDD) - weird things happen if this // call isn't made (this is done in two different places, in hopes // of squashing this stupid bug) XtUngrabButton(core->getDrawAreaWidget(), AnyButton, AnyModifier); } void XPDFViewer::cmdPrevPage(GString *args[], int nArgs, XEvent *event) { core->gotoPrevPage(1, gTrue, gFalse); } void XPDFViewer::cmdPrevPageNoScroll(GString *args[], int nArgs, XEvent *event) { core->gotoPrevPage(1, gFalse, gFalse); } void XPDFViewer::cmdPrint(GString *args[], int nArgs, XEvent *event) { XtManageChild(printDialog); } void XPDFViewer::cmdQuit(GString *args[], int nArgs, XEvent *event) { app->quit(); } void XPDFViewer::cmdRaise(GString *args[], int nArgs, XEvent *event) { XMapRaised(display, XtWindow(win)); XFlush(display); } void XPDFViewer::cmdRedraw(GString *args[], int nArgs, XEvent *event) { displayPage(core->getPageNum(), core->getZoom(), core->getRotate(), gFalse, gFalse); } void XPDFViewer::cmdReload(GString *args[], int nArgs, XEvent *event) { reloadFile(); } void XPDFViewer::cmdRotateCCW(GString *args[], int nArgs, XEvent *event) { int r; r = core->getRotate(); r = (r == 0) ? 270 : r - 90; displayPage(core->getPageNum(), core->getZoom(), r, gTrue, gFalse); } void XPDFViewer::cmdRotateCW(GString *args[], int nArgs, XEvent *event) { int r; r = core->getRotate(); r = (r == 270) ? 0 : r + 90; displayPage(core->getPageNum(), core->getZoom(), r, gTrue, gFalse); } void XPDFViewer::cmdRun(GString *args[], int nArgs, XEvent *event) { GString *fmt, *cmd, *s; LinkAction *action; double selLRX, selLRY, selURX, selURY, mouseX, mouseY; int selPage, mousePage; GBool gotSel, gotMouse; char buf[64]; char *p; char c0, c1; int i; cmd = new GString(); fmt = args[0]; i = 0; gotSel = gotMouse = gFalse; while (i < fmt->getLength()) { c0 = fmt->getChar(i); if (c0 == '%' && i+1 < fmt->getLength()) { c1 = fmt->getChar(i+1); switch (c1) { case 'f': if (core->getDoc() && (s = core->getDoc()->getFileName())) { cmd->append(s); } break; case 'b': if (core->getDoc() && (s = core->getDoc()->getFileName())) { if ((p = strrchr(s->getCString(), '.'))) { cmd->append(s->getCString(), p - s->getCString()); } else { cmd->append(s); } } break; case 'u': if ((action = core->getLinkAction()) && action->getKind() == actionURI) { s = core->mungeURL(((LinkURI *)action)->getURI()); cmd->append(s); delete s; } break; case 'p': if (core->getDoc()) { sprintf(buf, "%d", core->getPageNum()); cmd->append(buf); } break; case 'x': case 'y': case 'X': case 'Y': if (!gotSel) { if (!core->getSelection(&selPage, &selURX, &selURY, &selLRX, &selLRY)) { selPage = 0; selURX = selURY = selLRX = selLRY = 0; } gotSel = gTrue; } sprintf(buf, "%g", (c1 == 'x') ? selURX : (c1 == 'y') ? selURY : (c1 == 'X') ? selLRX : selLRY); cmd->append(buf); break; case 'i': case 'j': case 'k': if (!gotMouse) { if (event->type == ButtonPress || event->type == ButtonRelease) { core->cvtWindowToUser(event->xbutton.x, event->xbutton.y, &mousePage, &mouseX, &mouseY); } else if (event->type == KeyPress) { core->cvtWindowToUser(event->xkey.x, event->xkey.y, &mousePage, &mouseX, &mouseY); } else { mousePage = 0; mouseX = mouseY = 0; } gotMouse = gTrue; } if (c1 == 'i') { sprintf(buf, "%d", mousePage); } else { sprintf(buf, "%g", (c1 == 'j') ? mouseX : mouseY); } cmd->append(buf); break; default: cmd->append(c1); break; } i += 2; } else { cmd->append(c0); ++i; } } #ifdef VMS cmd->insert(0, "spawn/nowait "); #elif defined(__EMX__) cmd->insert(0, "start /min /n "); #else cmd->append(" &"); #endif system(cmd->getCString()); delete cmd; } void XPDFViewer::cmdScrollDown(GString *args[], int nArgs, XEvent *event) { core->scrollDown(atoi(args[0]->getCString())); } void XPDFViewer::cmdScrollDownNextPage(GString *args[], int nArgs, XEvent *event) { core->scrollDownNextPage(atoi(args[0]->getCString())); } void XPDFViewer::cmdScrollLeft(GString *args[], int nArgs, XEvent *event) { core->scrollLeft(atoi(args[0]->getCString())); } void XPDFViewer::cmdScrollOutlineDown(GString *args[], int nArgs, XEvent *event) { #ifndef DISABLE_OUTLINE Widget sb; int val, inc, pageInc, m, slider; if (outlineScroll == None) { return; } if ((sb = XtNameToWidget(outlineScroll, "VertScrollBar"))) { XtVaGetValues(sb, XmNvalue, &val, XmNincrement, &inc, XmNpageIncrement, &pageInc, XmNmaximum, &m, XmNsliderSize, &slider, NULL); if ((val += inc * atoi(args[0]->getCString())) > m - slider) { val = m - slider; } XmScrollBarSetValues(sb, val, slider, inc, pageInc, True); } #endif } void XPDFViewer::cmdScrollOutlineUp(GString *args[], int nArgs, XEvent *event) { #ifndef DISABLE_OUTLINE Widget sb; int val, inc, pageInc, m, slider; if (outlineScroll == None) { return; } if ((sb = XtNameToWidget(outlineScroll, "VertScrollBar"))) { XtVaGetValues(sb, XmNvalue, &val, XmNincrement, &inc, XmNpageIncrement, &pageInc, XmNminimum, &m, XmNsliderSize, &slider, NULL); if ((val -= inc * atoi(args[0]->getCString())) < m) { val = m; } XmScrollBarSetValues(sb, val, slider, inc, pageInc, True); } #endif } void XPDFViewer::cmdScrollRight(GString *args[], int nArgs, XEvent *event) { core->scrollRight(atoi(args[0]->getCString())); } void XPDFViewer::cmdScrollToBottomEdge(GString *args[], int nArgs, XEvent *event) { core->scrollToBottomEdge(); } void XPDFViewer::cmdScrollToBottomRight(GString *args[], int nArgs, XEvent *event) { core->scrollToBottomRight(); } void XPDFViewer::cmdScrollToLeftEdge(GString *args[], int nArgs, XEvent *event) { core->scrollToLeftEdge(); } void XPDFViewer::cmdScrollToRightEdge(GString *args[], int nArgs, XEvent *event) { core->scrollToRightEdge(); } void XPDFViewer::cmdScrollToTopEdge(GString *args[], int nArgs, XEvent *event) { core->scrollToTopEdge(); } void XPDFViewer::cmdScrollToTopLeft(GString *args[], int nArgs, XEvent *event) { core->scrollToTopLeft(); } void XPDFViewer::cmdScrollUp(GString *args[], int nArgs, XEvent *event) { core->scrollUp(atoi(args[0]->getCString())); } void XPDFViewer::cmdScrollUpPrevPage(GString *args[], int nArgs, XEvent *event) { core->scrollUpPrevPage(atoi(args[0]->getCString())); } void XPDFViewer::cmdSetSelection(GString *args[], int nArgs, XEvent *event) { int pg, ulx, uly, lrx, lry; pg = atoi(args[0]->getCString()); core->cvtUserToDev(core->getPageNum(), atof(args[1]->getCString()), atof(args[2]->getCString()), &ulx, &uly); core->cvtUserToDev(core->getPageNum(), atof(args[3]->getCString()), atof(args[4]->getCString()), &lrx, &lry); core->setSelection(pg, ulx, uly, lrx, lry); } void XPDFViewer::cmdSinglePageMode(GString *args[], int nArgs, XEvent *event) { Widget btn; if (!core->getContinuousMode()) { return; } core->setContinuousMode(gFalse); btn = XtNameToWidget(popupMenu, "continuousMode"); XtVaSetValues(btn, XmNset, XmUNSET, NULL); } void XPDFViewer::cmdStartPan(GString *args[], int nArgs, XEvent *event) { core->startPan(mouseX(event), mouseY(event)); } void XPDFViewer::cmdStartSelection(GString *args[], int nArgs, XEvent *event) { core->startSelection(mouseX(event), mouseY(event)); } void XPDFViewer::cmdToggleContinuousMode(GString *args[], int nArgs, XEvent *event) { if (core->getContinuousMode()) { cmdSinglePageMode(NULL, 0, event); } else { cmdContinuousMode(NULL, 0, event); } } void XPDFViewer::cmdToggleFullScreenMode(GString *args[], int nArgs, XEvent *event) { if (core->getFullScreen()) { cmdWindowMode(NULL, 0, event); } else { cmdFullScreenMode(NULL, 0, event); } } void XPDFViewer::cmdToggleOutline(GString *args[], int nArgs, XEvent *event) { #ifndef DISABLE_OUTLINE Dimension w; if (outlineScroll == None) { return; } XtVaGetValues(outlineScroll, XmNwidth, &w, NULL); if (w > 1) { cmdCloseOutline(NULL, 0, event); } else { cmdOpenOutline(NULL, 0, event); } #endif } void XPDFViewer::cmdWindowMode(GString *args[], int nArgs, XEvent *event) { PDFDoc *doc; XPDFViewer *viewer; int pg; Widget btn; if (!core->getFullScreen()) { return; } pg = core->getPageNum(); XtPopdown(win); doc = core->takeDoc(gFalse); viewer = app->reopen(this, doc, pg, gFalse); btn = XtNameToWidget(viewer->popupMenu, "fullScreen"); XtVaSetValues(btn, XmNset, XmUNSET, NULL); } void XPDFViewer::cmdZoomFitPage(GString *args[], int nArgs, XEvent *event) { if (core->getZoom() != zoomPage) { setZoomIdx(zoomPageIdx); displayPage(core->getPageNum(), zoomPage, core->getRotate(), gTrue, gFalse); } } void XPDFViewer::cmdZoomFitWidth(GString *args[], int nArgs, XEvent *event) { if (core->getZoom() != zoomWidth) { setZoomIdx(zoomWidthIdx); displayPage(core->getPageNum(), zoomWidth, core->getRotate(), gTrue, gFalse); } } void XPDFViewer::cmdZoomIn(GString *args[], int nArgs, XEvent *event) { int z; z = getZoomIdx(); if (z <= minZoomIdx && z > maxZoomIdx) { --z; setZoomIdx(z); displayPage(core->getPageNum(), zoomMenuInfo[z].zoom, core->getRotate(), gTrue, gFalse); } } void XPDFViewer::cmdZoomOut(GString *args[], int nArgs, XEvent *event) { int z; z = getZoomIdx(); if (z < minZoomIdx && z >= maxZoomIdx) { ++z; setZoomIdx(z); displayPage(core->getPageNum(), zoomMenuInfo[z].zoom, core->getRotate(), gTrue, gFalse); } } void XPDFViewer::cmdZoomPercent(GString *args[], int nArgs, XEvent *event) { double z; z = atof(args[0]->getCString()); setZoomVal(z); displayPage(core->getPageNum(), z, core->getRotate(), gTrue, gFalse); } void XPDFViewer::cmdZoomToSelection(GString *args[], int nArgs, XEvent *event) { int pg; double ulx, uly, lrx, lry; if (core->getSelection(&pg, &ulx, &uly, &lrx, &lry)) { core->zoomToRect(pg, ulx, uly, lrx, lry); } } //------------------------------------------------------------------------ // GUI code: main window //------------------------------------------------------------------------ void XPDFViewer::initWindow(GBool fullScreen) { Colormap colormap; XColor xcol; Atom state, val; Arg args[20]; int n; char *title; display = XtDisplay(app->getAppShell()); screenNum = XScreenNumberOfScreen(XtScreen(app->getAppShell())); toolBar = None; #ifndef DISABLE_OUTLINE outlineScroll = None; #endif // private colormap if (app->getInstallCmap()) { XtVaGetValues(app->getAppShell(), XmNcolormap, &colormap, NULL); // ensure that BlackPixel and WhitePixel are reserved in the // new colormap xcol.red = xcol.green = xcol.blue = 0; XAllocColor(display, colormap, &xcol); xcol.red = xcol.green = xcol.blue = 65535; XAllocColor(display, colormap, &xcol); colormap = XCopyColormapAndFree(display, colormap); } // top-level window n = 0; title = app->getTitle() ? app->getTitle()->getCString() : (char *)xpdfAppName; XtSetArg(args[n], XmNtitle, title); ++n; XtSetArg(args[n], XmNiconName, title); ++n; XtSetArg(args[n], XmNminWidth, 100); ++n; XtSetArg(args[n], XmNminHeight, 100); ++n; XtSetArg(args[n], XmNbaseWidth, 0); ++n; XtSetArg(args[n], XmNbaseHeight, 0); ++n; XtSetArg(args[n], XmNdeleteResponse, XmDO_NOTHING); ++n; win = XtCreatePopupShell("win", topLevelShellWidgetClass, app->getAppShell(), args, n); if (app->getInstallCmap()) { XtVaSetValues(win, XmNcolormap, colormap, NULL); } XmAddWMProtocolCallback(win, XInternAtom(display, "WM_DELETE_WINDOW", False), &closeMsgCbk, this); // create the full-screen window if (fullScreen) { initCore(win, gTrue); // create the normal (non-full-screen) window } else { if (app->getGeometry()) { n = 0; XtSetArg(args[n], XmNgeometry, app->getGeometry()->getCString()); ++n; XtSetValues(win, args, n); } n = 0; form = XmCreateForm(win, "form", args, n); XtManageChild(form); #ifdef DISABLE_OUTLINE initToolbar(form); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetValues(toolBar, args, n); initCore(form, gFalse); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, toolBar); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetValues(core->getWidget(), args, n); #else initToolbar(form); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetValues(toolBar, args, n); initPanedWin(form); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, toolBar); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetValues(panedWin, args, n); initCore(panedWin, fullScreen); n = 0; XtSetArg(args[n], XmNpositionIndex, 1); ++n; XtSetArg(args[n], XmNallowResize, True); ++n; XtSetArg(args[n], XmNpaneMinimum, 1); ++n; XtSetArg(args[n], XmNpaneMaximum, 10000); ++n; XtSetValues(core->getWidget(), args, n); #endif } // set the zoom menu to match the initial zoom setting setZoomVal(core->getZoom()); // set traversal order XtVaSetValues(core->getDrawAreaWidget(), XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); if (toolBar != None) { XtVaSetValues(backBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(prevTenPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(prevPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(nextPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(nextTenPageBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(forwardBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(pageNumText, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(zoomWidget, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(findBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(printBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(aboutBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); XtVaSetValues(quitBtn, XmNnavigationType, XmEXCLUSIVE_TAB_GROUP, NULL); } initPopupMenu(); if (fullScreen) { // Set both the old-style Motif decorations hint and the new-style // _NET_WM_STATE property. This is redundant, but might be useful // for older window managers. We also set the geometry to +0+0 to // avoid interactive placement. (Note: we need to realize the // shell, so it has a Window on which to set the _NET_WM_STATE // property, but we don't want to map it until later, so we set // mappedWhenManaged to false.) n = 0; XtSetArg(args[n], XmNmappedWhenManaged, False); ++n; XtSetArg(args[n], XmNmwmDecorations, 0); ++n; XtSetArg(args[n], XmNgeometry, "+0+0"); ++n; XtSetValues(win, args, n); XtRealizeWidget(win); state = XInternAtom(display, "_NET_WM_STATE", False); val = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False); XChangeProperty(display, XtWindow(win), state, XA_ATOM, 32, PropModeReplace, (Guchar *)&val, 1); } } void XPDFViewer::initToolbar(Widget parent) { Widget label, lastBtn; #ifndef USE_COMBO_BOX Widget btn; #endif Arg args[20]; int n; XmString s, emptyString; int i; // toolbar n = 0; toolBar = XmCreateForm(parent, "toolBar", args, n); XtManageChild(toolBar); // create an empty string -- this is used for buttons that will get // pixmaps later emptyString = XmStringCreateLocalized(""); // page movement buttons n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; backBtn = XmCreatePushButton(toolBar, "back", args, n); addToolTip(backBtn, "Back"); XtManageChild(backBtn); XtAddCallback(backBtn, XmNactivateCallback, &backCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, backBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; prevTenPageBtn = XmCreatePushButton(toolBar, "prevTenPage", args, n); addToolTip(prevTenPageBtn, "-10 pages"); XtManageChild(prevTenPageBtn); XtAddCallback(prevTenPageBtn, XmNactivateCallback, &prevTenPageCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, prevTenPageBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; prevPageBtn = XmCreatePushButton(toolBar, "prevPage", args, n); addToolTip(prevPageBtn, "Previous page"); XtManageChild(prevPageBtn); XtAddCallback(prevPageBtn, XmNactivateCallback, &prevPageCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, prevPageBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; nextPageBtn = XmCreatePushButton(toolBar, "nextPage", args, n); addToolTip(nextPageBtn, "Next page"); XtManageChild(nextPageBtn); XtAddCallback(nextPageBtn, XmNactivateCallback, &nextPageCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, nextPageBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; nextTenPageBtn = XmCreatePushButton(toolBar, "nextTenPage", args, n); addToolTip(nextTenPageBtn, "+10 pages"); XtManageChild(nextTenPageBtn); XtAddCallback(nextTenPageBtn, XmNactivateCallback, &nextTenPageCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, nextTenPageBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; forwardBtn = XmCreatePushButton(toolBar, "forward", args, n); addToolTip(forwardBtn, "Forward"); XtManageChild(forwardBtn); XtAddCallback(forwardBtn, XmNactivateCallback, &forwardCbk, (XtPointer)this); // page number display n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, forwardBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; s = XmStringCreateLocalized("Page "); XtSetArg(args[n], XmNlabelString, s); ++n; label = XmCreateLabel(toolBar, "pageLabel", args, n); XmStringFree(s); XtManageChild(label); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, label); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 3); ++n; XtSetArg(args[n], XmNmarginHeight, 3); ++n; XtSetArg(args[n], XmNcolumns, 5); ++n; pageNumText = XmCreateTextField(toolBar, "pageNum", args, n); XtManageChild(pageNumText); XtAddCallback(pageNumText, XmNactivateCallback, &pageNumCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, pageNumText); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; s = XmStringCreateLocalized(" of 00000"); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); ++n; XtSetArg(args[n], XmNrecomputeSize, False); ++n; pageCountLabel = XmCreateLabel(toolBar, "pageCountLabel", args, n); XmStringFree(s); XtManageChild(pageCountLabel); s = XmStringCreateLocalized(" of 0"); XtVaSetValues(pageCountLabel, XmNlabelString, s, NULL); XmStringFree(s); // zoom menu #if USE_COMBO_BOX XmString st[nZoomMenuItems]; n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, pageCountLabel); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 0); ++n; XtSetArg(args[n], XmNmarginHeight, 0); ++n; XtSetArg(args[n], XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); ++n; XtSetArg(args[n], XmNpositionMode, XmONE_BASED); ++n; XtSetArg(args[n], XmNcolumns, 7); ++n; for (i = 0; i < nZoomMenuItems; ++i) { st[i] = XmStringCreateLocalized((char *)zoomMenuInfo[i].label); } XtSetArg(args[n], XmNitems, st); ++n; XtSetArg(args[n], XmNitemCount, nZoomMenuItems); ++n; zoomComboBox = XmCreateComboBox(toolBar, "zoomComboBox", args, n); for (i = 0; i < nZoomMenuItems; ++i) { XmStringFree(st[i]); } addToolTip(zoomComboBox, "Zoom"); XtAddCallback(zoomComboBox, XmNselectionCallback, &zoomComboBoxCbk, (XtPointer)this); XtManageChild(zoomComboBox); zoomWidget = zoomComboBox; #else Widget menuPane; char buf[16]; n = 0; menuPane = XmCreatePulldownMenu(toolBar, "zoomMenuPane", args, n); for (i = 0; i < nZoomMenuItems; ++i) { n = 0; s = XmStringCreateLocalized(zoomMenuInfo[i].label); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNuserData, (XtPointer)i); ++n; sprintf(buf, "zoom%d", i); btn = XmCreatePushButton(menuPane, buf, args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &zoomMenuCbk, (XtPointer)this); zoomMenuBtns[i] = btn; } n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, pageCountLabel); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 0); ++n; XtSetArg(args[n], XmNmarginHeight, 0); ++n; XtSetArg(args[n], XmNsubMenuId, menuPane); ++n; zoomMenu = XmCreateOptionMenu(toolBar, "zoomMenu", args, n); addToolTip(zoomMenu, "Zoom"); XtManageChild(zoomMenu); zoomWidget = zoomMenu; #endif // find/print/about buttons n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, zoomWidget); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; findBtn = XmCreatePushButton(toolBar, "find", args, n); addToolTip(findBtn, "Find"); XtManageChild(findBtn); XtAddCallback(findBtn, XmNactivateCallback, &findCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, findBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; printBtn = XmCreatePushButton(toolBar, "print", args, n); addToolTip(printBtn, "Print"); XtManageChild(printBtn); XtAddCallback(printBtn, XmNactivateCallback, &printCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, printBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; XtSetArg(args[n], XmNlabelString, emptyString); ++n; aboutBtn = XmCreatePushButton(toolBar, "about", args, n); addToolTip(aboutBtn, "About / help"); XtManageChild(aboutBtn); XtAddCallback(aboutBtn, XmNactivateCallback, &aboutCbk, (XtPointer)this); lastBtn = aboutBtn; // quit button n = 0; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNmarginWidth, 6); ++n; s = XmStringCreateLocalized("Quit"); XtSetArg(args[n], XmNlabelString, s); ++n; quitBtn = XmCreatePushButton(toolBar, "quit", args, n); XmStringFree(s); XtManageChild(quitBtn); XtAddCallback(quitBtn, XmNactivateCallback, &quitCbk, (XtPointer)this); // link label n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, lastBtn); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNrightWidget, quitBtn); ++n; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; s = XmStringCreateLocalized(""); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNrecomputeSize, True); ++n; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); ++n; linkLabel = XmCreateLabel(toolBar, "linkLabel", args, n); XmStringFree(s); XtManageChild(linkLabel); XmStringFree(emptyString); } #ifndef DISABLE_OUTLINE void XPDFViewer::initPanedWin(Widget parent) { Widget clipWin; Arg args[20]; int n; // paned window n = 0; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; #if defined(__sgi) && (XmVERSION <= 1) panedWin = SgCreateHorzPanedWindow(parent, "panedWin", args, n); #else panedWin = XmCreatePanedWindow(parent, "panedWin", args, n); #endif XtManageChild(panedWin); // scrolled window for outline container n = 0; XtSetArg(args[n], XmNpositionIndex, 0); ++n; XtSetArg(args[n], XmNallowResize, True); ++n; XtSetArg(args[n], XmNpaneMinimum, 1); ++n; XtSetArg(args[n], XmNpaneMaximum, 10000); ++n; #if !(defined(__sgi) && (XmVERSION <= 1)) XtSetArg(args[n], XmNwidth, 1); ++n; #endif XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n; outlineScroll = XmCreateScrolledWindow(panedWin, "outlineScroll", args, n); XtManageChild(outlineScroll); XtVaGetValues(outlineScroll, XmNclipWindow, &clipWin, NULL); XtVaSetValues(clipWin, XmNbackground, app->getPaperPixel(), NULL); // outline tree n = 0; XtSetArg(args[n], XmNbackground, app->getPaperPixel()); ++n; outlineTree = XPDFCreateTree(outlineScroll, "outlineTree", args, n); XtManageChild(outlineTree); XtAddCallback(outlineTree, XPDFNselectionCallback, &outlineSelectCbk, (XtPointer)this); } #endif void XPDFViewer::initCore(Widget parent, GBool fullScreen) { core = new XPDFCore(win, parent, app->getPaperRGB(), app->getPaperPixel(), app->getMattePixel(fullScreen), fullScreen, app->getReverseVideo(), app->getInstallCmap(), app->getRGBCubeSize()); core->setUpdateCbk(&updateCbk, this); core->setActionCbk(&actionCbk, this); core->setKeyPressCbk(&keyPressCbk, this); core->setMouseCbk(&mouseCbk, this); } void XPDFViewer::initPopupMenu() { Widget btn; Arg args[20]; int n; XmString s, s2; n = 0; #if XmVersion < 1002 // older versions of Motif need this, newer ones choke on it, // sometimes not displaying the menu at all, maybe depending on the // state of the NumLock key (taken from DDD) XtSetArg(args[n], XmNmenuPost, ""); ++n; #endif popupMenu = XmCreatePopupMenu(core->getDrawAreaWidget(), "popupMenu", args, n); n = 0; s = XmStringCreateLocalized("Open..."); XtSetArg(args[n], XmNlabelString, s); ++n; s2 = XmStringCreateLocalized("O"); XtSetArg(args[n], XmNacceleratorText, s2); ++n; btn = XmCreatePushButton(popupMenu, "open", args, n); XmStringFree(s); XmStringFree(s2); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &openCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Open in new window..."); XtSetArg(args[n], XmNlabelString, s); ++n; btn = XmCreatePushButton(popupMenu, "openInNewWindow", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &openInNewWindowCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Reload"); XtSetArg(args[n], XmNlabelString, s); ++n; s2 = XmStringCreateLocalized("R"); XtSetArg(args[n], XmNacceleratorText, s2); ++n; btn = XmCreatePushButton(popupMenu, "reload", args, n); XmStringFree(s); XmStringFree(s2); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &reloadCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Save as..."); XtSetArg(args[n], XmNlabelString, s); ++n; btn = XmCreatePushButton(popupMenu, "saveAs", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &saveAsCbk, (XtPointer)this); n = 0; btn = XmCreateSeparator(popupMenu, "sep1", args, n); XtManageChild(btn); n = 0; s = XmStringCreateLocalized("Continuous view"); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNindicatorType, XmN_OF_MANY); ++n; XtSetArg(args[n], XmNvisibleWhenOff, True); ++n; XtSetArg(args[n], XmNset, core->getContinuousMode() ? XmSET : XmUNSET); ++n; btn = XmCreateToggleButton(popupMenu, "continuousMode", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNvalueChangedCallback, &continuousModeToggleCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Full screen"); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNindicatorType, XmN_OF_MANY); ++n; XtSetArg(args[n], XmNvisibleWhenOff, True); ++n; XtSetArg(args[n], XmNset, core->getFullScreen() ? XmSET : XmUNSET); ++n; btn = XmCreateToggleButton(popupMenu, "fullScreen", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNvalueChangedCallback, &fullScreenToggleCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Rotate counterclockwise"); XtSetArg(args[n], XmNlabelString, s); ++n; btn = XmCreatePushButton(popupMenu, "rotateCCW", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &rotateCCWCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Rotate clockwise"); XtSetArg(args[n], XmNlabelString, s); ++n; btn = XmCreatePushButton(popupMenu, "rotateCW", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &rotateCWCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Zoom to selection"); XtSetArg(args[n], XmNlabelString, s); ++n; btn = XmCreatePushButton(popupMenu, "zoomToSelection", args, n); XmStringFree(s); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &zoomToSelectionCbk, (XtPointer)this); n = 0; btn = XmCreateSeparator(popupMenu, "sep2", args, n); XtManageChild(btn); n = 0; s = XmStringCreateLocalized("Close"); XtSetArg(args[n], XmNlabelString, s); ++n; s2 = XmStringCreateLocalized("Ctrl+W"); XtSetArg(args[n], XmNacceleratorText, s2); ++n; btn = XmCreatePushButton(popupMenu, "close", args, n); XmStringFree(s); XmStringFree(s2); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &closeCbk, (XtPointer)this); n = 0; s = XmStringCreateLocalized("Quit"); XtSetArg(args[n], XmNlabelString, s); ++n; s2 = XmStringCreateLocalized("Q"); XtSetArg(args[n], XmNacceleratorText, s2); ++n; btn = XmCreatePushButton(popupMenu, "quit", args, n); XmStringFree(s); XmStringFree(s2); XtManageChild(btn); XtAddCallback(btn, XmNactivateCallback, &quitCbk, (XtPointer)this); // this is magic (taken from DDD) - weird things happen if this // call isn't made XtUngrabButton(core->getDrawAreaWidget(), AnyButton, AnyModifier); } void XPDFViewer::addToolTip(Widget widget, char *text) { #ifdef XmNtoolTipString XmString s; Cardinal n, i; WidgetList children; if (XtIsComposite(widget)) { XtVaGetValues(widget, XmNnumChildren, &n, XmNchildren, &children, NULL); for (i = 0; i < n; ++i) { addToolTip(children[i], text); } } else { s = XmStringCreateLocalized(text); XtVaSetValues(widget, XmNtoolTipString, s, NULL); XmStringFree(s); } #endif } void XPDFViewer::mapWindow() { #ifdef HAVE_X11_XPM_H Pixmap iconPixmap; #endif int depth; Pixel fg, bg, arm; // show the window XtPopup(win, XtGrabNone); core->takeFocus(); // create the icon #ifdef HAVE_X11_XPM_H if (XpmCreatePixmapFromData(display, XtWindow(win), xpdfIcon, &iconPixmap, NULL, NULL) == XpmSuccess) { XtVaSetValues(win, XmNiconPixmap, iconPixmap, NULL); } #endif // set button bitmaps (must be done after the window is mapped) if (toolBar != None) { XtVaGetValues(backBtn, XmNdepth, &depth, XmNforeground, &fg, XmNbackground, &bg, XmNarmColor, &arm, NULL); XtVaSetValues(backBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)backArrow_bits, backArrow_width, backArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)backArrow_bits, backArrow_width, backArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)backArrowDis_bits, backArrowDis_width, backArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(prevTenPageBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblLeftArrow_bits, dblLeftArrow_width, dblLeftArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblLeftArrow_bits, dblLeftArrow_width, dblLeftArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblLeftArrowDis_bits, dblLeftArrowDis_width, dblLeftArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(prevPageBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)leftArrow_bits, leftArrow_width, leftArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)leftArrow_bits, leftArrow_width, leftArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)leftArrowDis_bits, leftArrowDis_width, leftArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(nextPageBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)rightArrow_bits, rightArrow_width, rightArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)rightArrow_bits, rightArrow_width, rightArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)rightArrowDis_bits, rightArrowDis_width, rightArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(nextTenPageBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblRightArrow_bits, dblRightArrow_width, dblRightArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblRightArrow_bits, dblRightArrow_width, dblRightArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)dblRightArrowDis_bits, dblRightArrowDis_width, dblRightArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(forwardBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)forwardArrow_bits, forwardArrow_width, forwardArrow_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)forwardArrow_bits, forwardArrow_width, forwardArrow_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)forwardArrowDis_bits, forwardArrowDis_width, forwardArrowDis_height, fg, bg, depth), NULL); XtVaSetValues(findBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)find_bits, find_width, find_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)find_bits, find_width, find_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)findDis_bits, findDis_width, findDis_height, fg, bg, depth), NULL); XtVaSetValues(printBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)print_bits, print_width, print_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)print_bits, print_width, print_height, fg, arm, depth), XmNlabelInsensitivePixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)printDis_bits, printDis_width, printDis_height, fg, bg, depth), NULL); XtVaSetValues(aboutBtn, XmNlabelType, XmPIXMAP, XmNlabelPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)about_bits, about_width, about_height, fg, bg, depth), XmNarmPixmap, XCreatePixmapFromBitmapData(display, XtWindow(toolBar), (char *)about_bits, about_width, about_height, fg, arm, depth), NULL); } } void XPDFViewer::closeWindow() { XtPopdown(win); XtDestroyWidget(win); } int XPDFViewer::getZoomIdx() { int i; for (i = 0; i < nZoomMenuItems; ++i) { if (core->getZoom() == zoomMenuInfo[i].zoom) { return i; } } return -1; } void XPDFViewer::setZoomIdx(int idx) { if (toolBar == None) { return; } #if USE_COMBO_BOX XtVaSetValues(zoomComboBox, XmNselectedPosition, idx + 1, NULL); #else XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[idx], NULL); #endif } void XPDFViewer::setZoomVal(double z) { if (toolBar == None) { return; } #if USE_COMBO_BOX char buf[32]; XmString s; int i; for (i = 0; i < nZoomMenuItems; ++i) { if (z == zoomMenuInfo[i].zoom) { XtVaSetValues(zoomComboBox, XmNselectedPosition, i + 1, NULL); return; } } sprintf(buf, "%d%%", (int)z); s = XmStringCreateLocalized(buf); XtVaSetValues(zoomComboBox, XmNselectedItem, s, NULL); XmStringFree(s); #else int i; for (i = 0; i < nZoomMenuItems; ++i) { if (z == zoomMenuInfo[i].zoom) { XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[i], NULL); return; } } for (i = maxZoomIdx; i < minZoomIdx; ++i) { if (z > zoomMenuInfo[i].zoom) { break; } } XtVaSetValues(zoomMenu, XmNmenuHistory, zoomMenuBtns[i], NULL); #endif } void XPDFViewer::prevPageCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->gotoPrevPage(1, gTrue, gFalse); viewer->core->takeFocus(); } void XPDFViewer::prevTenPageCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->gotoPrevPage(10, gTrue, gFalse); viewer->core->takeFocus(); } void XPDFViewer::nextPageCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->gotoNextPage(1, gTrue); viewer->core->takeFocus(); } void XPDFViewer::nextTenPageCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->gotoNextPage(10, gTrue); viewer->core->takeFocus(); } void XPDFViewer::backCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->goBackward(); viewer->core->takeFocus(); } void XPDFViewer::forwardCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->core->goForward(); viewer->core->takeFocus(); } #if USE_COMBO_BOX void XPDFViewer::zoomComboBoxCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmComboBoxCallbackStruct *data = (XmComboBoxCallbackStruct *)callData; double z; char *s; XmStringContext context; XmStringCharSet charSet; XmStringDirection dir; Boolean sep; z = viewer->core->getZoom(); if (data->item_position == 0) { XmStringInitContext(&context, data->item_or_text); if (XmStringGetNextSegment(context, &s, &charSet, &dir, &sep)) { z = atof(s); if (z <= 1) { z = defZoom; } XtFree(charSet); XtFree(s); } XmStringFreeContext(context); } else { z = zoomMenuInfo[data->item_position - 1].zoom; } // only redraw if this was triggered by an event; otherwise // the caller is responsible for doing the redraw if (z != viewer->core->getZoom() && data->event) { viewer->displayPage(viewer->core->getPageNum(), z, viewer->core->getRotate(), gTrue, gFalse); } viewer->core->takeFocus(); } #else // USE_COMBO_BOX void XPDFViewer::zoomMenuCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmPushButtonCallbackStruct *data = (XmPushButtonCallbackStruct *)callData; XtPointer userData; double z; XtVaGetValues(widget, XmNuserData, &userData, NULL); z = zoomMenuInfo[(long)userData].zoom; // only redraw if this was triggered by an event; otherwise // the caller is responsible for doing the redraw if (z != viewer->core->getZoom() && data->event) { viewer->displayPage(viewer->core->getPageNum(), z, viewer->core->getRotate(), gTrue, gFalse); } viewer->core->takeFocus(); } #endif // USE_COMBO_BOX void XPDFViewer::findCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; if (!viewer->core->getDoc()) { return; } viewer->mapFindDialog(); } void XPDFViewer::printCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; if (!viewer->core->getDoc()) { return; } XtManageChild(viewer->printDialog); } void XPDFViewer::aboutCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XtManageChild(viewer->aboutDialog); } void XPDFViewer::quitCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->app->quit(); } void XPDFViewer::openCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->mapOpenDialog(gFalse); } void XPDFViewer::openInNewWindowCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->mapOpenDialog(gTrue); } void XPDFViewer::reloadCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->reloadFile(); } void XPDFViewer::saveAsCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; if (!viewer->core->getDoc()) { return; } viewer->mapSaveAsDialog(); } void XPDFViewer::continuousModeToggleCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmToggleButtonCallbackStruct *data = (XmToggleButtonCallbackStruct *)callData; viewer->core->setContinuousMode(data->set == XmSET); } void XPDFViewer::fullScreenToggleCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmToggleButtonCallbackStruct *data = (XmToggleButtonCallbackStruct *)callData; if (data->set == XmSET) { viewer->cmdFullScreenMode(NULL, 0, NULL); } else { viewer->cmdWindowMode(NULL, 0, NULL); } } void XPDFViewer::rotateCCWCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->cmdRotateCCW(NULL, 0, NULL); } void XPDFViewer::rotateCWCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->cmdRotateCW(NULL, 0, NULL); } void XPDFViewer::zoomToSelectionCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; int pg; double ulx, uly, lrx, lry; if (viewer->core->getSelection(&pg, &ulx, &uly, &lrx, &lry)) { viewer->core->zoomToRect(pg, ulx, uly, lrx, lry); } } void XPDFViewer::closeCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->app->close(viewer, gFalse); } void XPDFViewer::closeMsgCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->app->close(viewer, gTrue); } void XPDFViewer::pageNumCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; char *s, *p; int pg; char buf[20]; if (!viewer->core->getDoc()) { goto err; } s = XmTextFieldGetString(viewer->pageNumText); for (p = s; *p; ++p) { if (!isdigit(*p)) { goto err; } } pg = atoi(s); if (pg < 1 || pg > viewer->core->getDoc()->getNumPages()) { goto err; } viewer->displayPage(pg, viewer->core->getZoom(), viewer->core->getRotate(), gFalse, gTrue); viewer->core->takeFocus(); return; err: XBell(viewer->display, 0); sprintf(buf, "%d", viewer->core->getPageNum()); XmTextFieldSetString(viewer->pageNumText, buf); } void XPDFViewer::updateCbk(void *data, GString *fileName, int pageNum, int numPages, const char *linkString) { XPDFViewer *viewer = (XPDFViewer *)data; GString *title; char buf[20]; XmString s; if (fileName) { if (!(title = viewer->app->getTitle())) { title = (new GString(xpdfAppName))->append(": ")->append(fileName); } XtVaSetValues(viewer->win, XmNtitle, title->getCString(), XmNiconName, title->getCString(), NULL); if (!viewer->app->getTitle()) { delete title; } #ifndef DISABLE_OUTLINE viewer->setupOutline(); #endif viewer->setupPrintDialog(); } if (viewer->toolBar != None) { if (pageNum >= 0) { s = XmStringCreateLocalized(""); XtVaSetValues(viewer->linkLabel, XmNlabelString, s, NULL); XmStringFree(s); sprintf(buf, "%d", pageNum); XmTextFieldSetString(viewer->pageNumText, buf); XtVaSetValues(viewer->prevTenPageBtn, XmNsensitive, pageNum > 1, NULL); XtVaSetValues(viewer->prevPageBtn, XmNsensitive, pageNum > 1, NULL); XtVaSetValues(viewer->nextTenPageBtn, XmNsensitive, pageNum < viewer->core->getDoc()->getNumPages(), NULL); XtVaSetValues(viewer->nextPageBtn, XmNsensitive, pageNum < viewer->core->getDoc()->getNumPages(), NULL); XtVaSetValues(viewer->backBtn, XmNsensitive, viewer->core->canGoBack(), NULL); XtVaSetValues(viewer->forwardBtn, XmNsensitive, viewer->core->canGoForward(), NULL); } if (numPages >= 0) { sprintf(buf, " of %d", numPages); s = XmStringCreateLocalized(buf); XtVaSetValues(viewer->pageCountLabel, XmNlabelString, s, NULL); XmStringFree(s); } if (linkString) { s = XmStringCreateLocalized((char *)linkString); XtVaSetValues(viewer->linkLabel, XmNlabelString, s, NULL); XmStringFree(s); } } } //------------------------------------------------------------------------ // GUI code: outline //------------------------------------------------------------------------ #ifndef DISABLE_OUTLINE void XPDFViewer::setupOutline() { GList *items; UnicodeMap *uMap; GString *enc; int i; if (outlineScroll == None) { return; } // unmanage and destroy the old labels if (outlineLabels) { XtUnmanageChildren(outlineLabels, outlineLabelsLength); for (i = 0; i < outlineLabelsLength; ++i) { XtDestroyWidget(outlineLabels[i]); } gfree(outlineLabels); outlineLabels = NULL; outlineLabelsLength = outlineLabelsSize = 0; } if (core->getDoc()) { // create the new labels items = core->getDoc()->getOutline()->getItems(); if (items && items->getLength() > 0) { enc = new GString("Latin1"); uMap = globalParams->getUnicodeMap(enc); delete enc; setupOutlineItems(items, NULL, uMap); uMap->decRefCnt(); } // manage the new labels XtManageChildren(outlineLabels, outlineLabelsLength); } } void XPDFViewer::setupOutlineItems(GList *items, Widget parent, UnicodeMap *uMap) { OutlineItem *item; GList *kids; Widget label; Arg args[20]; GString *title; char buf[8]; XmString s; int i, j, n; for (i = 0; i < items->getLength(); ++i) { item = (OutlineItem *)items->get(i); title = new GString(); for (j = 0; j < item->getTitleLength(); ++j) { n = uMap->mapUnicode(item->getTitle()[j], buf, sizeof(buf)); title->append(buf, n); } n = 0; XtSetArg(args[n], XPDFNentryPosition, i); ++n; if (parent) { XtSetArg(args[n], XPDFNentryParent, parent); ++n; } XtSetArg(args[n], XPDFNentryExpanded, item->isOpen()); ++n; s = XmStringCreateLocalized(title->getCString()); delete title; XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNuserData, item); ++n; XtSetArg(args[n], XmNmarginWidth, 0); ++n; XtSetArg(args[n], XmNmarginHeight, 2); ++n; XtSetArg(args[n], XmNshadowThickness, 0); ++n; XtSetArg(args[n], XmNforeground, app->getReverseVideo() ? WhitePixel(display, screenNum) : BlackPixel(display, screenNum)); ++n; XtSetArg(args[n], XmNbackground, app->getPaperPixel()); ++n; label = XmCreateLabelGadget(outlineTree, "label", args, n); XmStringFree(s); if (outlineLabelsLength == outlineLabelsSize) { outlineLabelsSize += 64; outlineLabels = (Widget *)greallocn(outlineLabels, outlineLabelsSize, sizeof(Widget *)); } outlineLabels[outlineLabelsLength++] = label; item->open(); if ((kids = item->getKids())) { setupOutlineItems(kids, label, uMap); } } } void XPDFViewer::outlineSelectCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XPDFTreeSelectCallbackStruct *data = (XPDFTreeSelectCallbackStruct *)callData; OutlineItem *item; XtVaGetValues(data->selectedItem, XmNuserData, &item, NULL); if (item) { if (item->getAction()) { viewer->core->doAction(item->getAction()); } } viewer->core->takeFocus(); } #endif // !DISABLE_OUTLINE //------------------------------------------------------------------------ // GUI code: "about" dialog //------------------------------------------------------------------------ void XPDFViewer::initAboutDialog() { Widget scrolledWin, col, label, sep, closeBtn; Arg args[20]; int n, i; XmString s; char buf[20]; //----- dialog n = 0; s = XmStringCreateLocalized(xpdfAppName ": About"); XtSetArg(args[n], XmNdialogTitle, s); ++n; XtSetArg(args[n], XmNwidth, 450); ++n; XtSetArg(args[n], XmNheight, 300); ++n; aboutDialog = XmCreateFormDialog(win, "aboutDialog", args, n); XmStringFree(s); //----- "close" button n = 0; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; closeBtn = XmCreatePushButton(aboutDialog, "Close", args, n); XtManageChild(closeBtn); n = 0; XtSetArg(args[n], XmNdefaultButton, closeBtn); ++n; XtSetArg(args[n], XmNcancelButton, closeBtn); ++n; XtSetValues(aboutDialog, args, n); //----- scrolled window and RowColumn n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, closeBtn); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNscrollingPolicy, XmAUTOMATIC); ++n; scrolledWin = XmCreateScrolledWindow(aboutDialog, "scrolledWin", args, n); XtManageChild(scrolledWin); n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); ++n; XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n; col = XmCreateRowColumn(scrolledWin, "col", args, n); XtManageChild(col); //----- fonts aboutBigFont = createFontList("-*-times-bold-i-normal--20-*-*-*-*-*-iso8859-1"); aboutVersionFont = createFontList("-*-times-medium-r-normal--16-*-*-*-*-*-iso8859-1"); aboutFixedFont = createFontList("-*-courier-medium-r-normal--12-*-*-*-*-*-iso8859-1"); //----- heading n = 0; s = XmStringCreateLocalized("Xpdf"); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutBigFont); ++n; label = XmCreateLabel(col, "h0", args, n); XmStringFree(s); XtManageChild(label); n = 0; s = XmStringCreateLocalized("Version " xpdfVersion); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n; label = XmCreateLabel(col, "h1", args, n); XmStringFree(s); XtManageChild(label); n = 0; s = XmStringCreateLocalized(xpdfCopyright); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n; label = XmCreateLabel(col, "h2", args, n); XmStringFree(s); XtManageChild(label); n = 0; s = XmStringCreateLocalized(" "); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n; label = XmCreateLabel(col, "h3", args, n); XmStringFree(s); XtManageChild(label); n = 0; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; sep = XmCreateSeparator(col, "sep", args, n); XtManageChild(sep); n = 0; s = XmStringCreateLocalized(" "); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutVersionFont); ++n; label = XmCreateLabel(col, "h4", args, n); XmStringFree(s); XtManageChild(label); n = 0; //----- text for (i = 0; aboutWinText[i]; ++i) { n = 0; s = XmStringCreateLocalized((char *)aboutWinText[i]); XtSetArg(args[n], XmNlabelString, s); ++n; XtSetArg(args[n], XmNfontList, aboutFixedFont); ++n; sprintf(buf, "t%d", i); label = XmCreateLabel(col, buf, args, n); XtManageChild(label); XmStringFree(s); } } //------------------------------------------------------------------------ // GUI code: "open" dialog //------------------------------------------------------------------------ void XPDFViewer::initOpenDialog() { Arg args[20]; int n; XmString s1, s2, s3; GString *dir; n = 0; s1 = XmStringCreateLocalized("Open"); XtSetArg(args[n], XmNokLabelString, s1); ++n; s2 = XmStringCreateLocalized("*.[Pp][Dd][Ff]"); XtSetArg(args[n], XmNpattern, s2); ++n; s3 = XmStringCreateLocalized(xpdfAppName ": Open"); XtSetArg(args[n], XmNdialogTitle, s3); ++n; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; XtSetArg(args[n], XmNautoUnmanage, True); ++n; openDialog = XmCreateFileSelectionDialog(win, "openDialog", args, n); XmStringFree(s1); XmStringFree(s2); XmStringFree(s3); XtUnmanageChild(XmFileSelectionBoxGetChild(openDialog, XmDIALOG_HELP_BUTTON)); XtAddCallback(openDialog, XmNokCallback, &openOkCbk, (XtPointer)this); if (core->getDoc() && core->getDoc()->getFileName()) { dir = makePathAbsolute(grabPath( core->getDoc()->getFileName()->getCString())); s1 = XmStringCreateLocalized(dir->getCString()); XtVaSetValues(openDialog, XmNdirectory, s1, NULL); XmStringFree(s1); delete dir; } } void XPDFViewer::mapOpenDialog(GBool openInNewWindowA) { if (!openDialog) { initOpenDialog(); } openInNewWindow = openInNewWindowA; XmFileSelectionDoSearch(openDialog, NULL); XtManageChild(openDialog); } void XPDFViewer::openOkCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmFileSelectionBoxCallbackStruct *data = (XmFileSelectionBoxCallbackStruct *)callData; char *fileName; XmStringContext context; XmStringCharSet charSet; XmStringDirection dir; Boolean sep; GString *fileNameStr; XmStringInitContext(&context, data->value); if (XmStringGetNextSegment(context, &fileName, &charSet, &dir, &sep)) { fileNameStr = new GString(fileName); if (viewer->openInNewWindow) { viewer->app->open(fileNameStr); } else { if (viewer->loadFile(fileNameStr)) { viewer->displayPage(1, viewer->core->getZoom(), viewer->core->getRotate(), gTrue, gTrue); } } delete fileNameStr; XtFree(charSet); XtFree(fileName); } XmStringFreeContext(context); } //------------------------------------------------------------------------ // GUI code: "find" dialog //------------------------------------------------------------------------ void XPDFViewer::initFindDialog() { Widget form1, label, okBtn, closeBtn; Arg args[20]; int n; XmString s; //----- dialog n = 0; s = XmStringCreateLocalized(xpdfAppName ": Find"); XtSetArg(args[n], XmNdialogTitle, s); ++n; XtSetArg(args[n], XmNnavigationType, XmNONE); ++n; XtSetArg(args[n], XmNautoUnmanage, False); ++n; findDialog = XmCreateFormDialog(win, "findDialog", args, n); XmStringFree(s); //----- "find" and "close" buttons n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n; okBtn = XmCreatePushButton(findDialog, "Find", args, n); XtManageChild(okBtn); XtAddCallback(okBtn, XmNactivateCallback, &findFindCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; XtSetArg(args[n], XmNnavigationType, XmEXCLUSIVE_TAB_GROUP); ++n; closeBtn = XmCreatePushButton(findDialog, "Close", args, n); XtManageChild(closeBtn); XtAddCallback(closeBtn, XmNactivateCallback, &findCloseCbk, (XtPointer)this); //----- checkboxes n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, okBtn); ++n; XtSetArg(args[n], XmNindicatorType, XmN_OF_MANY); ++n; #if XmVERSION <= 1 XtSetArg(args[n], XmNindicatorOn, True); ++n; #else XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); ++n; #endif XtSetArg(args[n], XmNset, XmUNSET); ++n; s = XmStringCreateLocalized("Search backward"); XtSetArg(args[n], XmNlabelString, s); ++n; findBackwardToggle = XmCreateToggleButton(findDialog, "backward", args, n); XmStringFree(s); XtManageChild(findBackwardToggle); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, findBackwardToggle); ++n; XtSetArg(args[n], XmNleftOffset, 16); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, okBtn); ++n; XtSetArg(args[n], XmNindicatorType, XmN_OF_MANY); ++n; #if XmVERSION <= 1 XtSetArg(args[n], XmNindicatorOn, True); ++n; #else XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); ++n; #endif XtSetArg(args[n], XmNset, XmUNSET); ++n; s = XmStringCreateLocalized("Match case"); XtSetArg(args[n], XmNlabelString, s); ++n; findCaseSensitiveToggle = XmCreateToggleButton(findDialog, "matchCase", args, n); XmStringFree(s); XtManageChild(findCaseSensitiveToggle); n = 0; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, findCaseSensitiveToggle); ++n; XtSetArg(args[n], XmNleftOffset, 16); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, okBtn); ++n; XtSetArg(args[n], XmNindicatorType, XmN_OF_MANY); ++n; #if XmVERSION <= 1 XtSetArg(args[n], XmNindicatorOn, True); ++n; #else XtSetArg(args[n], XmNindicatorOn, XmINDICATOR_FILL); ++n; #endif XtSetArg(args[n], XmNset, XmUNSET); ++n; s = XmStringCreateLocalized("Whole words only"); XtSetArg(args[n], XmNlabelString, s); ++n; findWholeWordToggle = XmCreateToggleButton(findDialog, "wholeWord", args, n); XmStringFree(s); XtManageChild(findWholeWordToggle); //----- search string entry n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNtopOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNbottomWidget, findBackwardToggle); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 2); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 2); ++n; form1 = XmCreateForm(findDialog, "form", args, n); XtManageChild(form1); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; s = XmStringCreateLocalized("Find text: "); XtSetArg(args[n], XmNlabelString, s); ++n; label = XmCreateLabel(form1, "label", args, n); XmStringFree(s); XtManageChild(label); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNleftWidget, label); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; findText = XmCreateTextField(form1, "text", args, n); XtManageChild(findText); #ifdef LESSTIF_VERSION XtAddCallback(findText, XmNactivateCallback, &findFindCbk, (XtPointer)this); #endif //----- dialog parameters n = 0; XtSetArg(args[n], XmNdefaultButton, okBtn); ++n; XtSetArg(args[n], XmNcancelButton, closeBtn); ++n; #if XmVersion > 1001 XtSetArg(args[n], XmNinitialFocus, findText); ++n; #endif XtSetValues(findDialog, args, n); } void XPDFViewer::findFindCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; viewer->doFind(gFalse); } void XPDFViewer::mapFindDialog() { XmTextFieldSetSelection(findText, 0, XmTextFieldGetLastPosition(findText), XtLastTimestampProcessed(display)); XmTextFieldSetInsertionPosition(findText, 0); XtManageChild(findDialog); } void XPDFViewer::doFind(GBool next) { if (XtWindow(findDialog)) { XDefineCursor(display, XtWindow(findDialog), core->getBusyCursor()); } core->find(XmTextFieldGetString(findText), XmToggleButtonGetState(findCaseSensitiveToggle), next, XmToggleButtonGetState(findBackwardToggle), XmToggleButtonGetState(findWholeWordToggle), gFalse); if (XtWindow(findDialog)) { XUndefineCursor(display, XtWindow(findDialog)); } } void XPDFViewer::findCloseCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XtUnmanageChild(viewer->findDialog); } //------------------------------------------------------------------------ // GUI code: "save as" dialog //------------------------------------------------------------------------ void XPDFViewer::initSaveAsDialog() { Arg args[20]; int n; XmString s1, s2, s3; GString *dir; n = 0; s1 = XmStringCreateLocalized("Save"); XtSetArg(args[n], XmNokLabelString, s1); ++n; s2 = XmStringCreateLocalized("*.[Pp][Dd][Ff]"); XtSetArg(args[n], XmNpattern, s2); ++n; s3 = XmStringCreateLocalized(xpdfAppName ": Save as"); XtSetArg(args[n], XmNdialogTitle, s3); ++n; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; XtSetArg(args[n], XmNautoUnmanage, True); ++n; saveAsDialog = XmCreateFileSelectionDialog(win, "saveAsDialog", args, n); XmStringFree(s1); XmStringFree(s2); XmStringFree(s3); XtUnmanageChild(XmFileSelectionBoxGetChild(saveAsDialog, XmDIALOG_HELP_BUTTON)); XtAddCallback(saveAsDialog, XmNokCallback, &saveAsOkCbk, (XtPointer)this); if (core->getDoc() && core->getDoc()->getFileName()) { dir = makePathAbsolute(grabPath( core->getDoc()->getFileName()->getCString())); s1 = XmStringCreateLocalized(dir->getCString()); XtVaSetValues(saveAsDialog, XmNdirectory, s1, NULL); XmStringFree(s1); delete dir; } } void XPDFViewer::mapSaveAsDialog() { if (!saveAsDialog) { initSaveAsDialog(); } XmFileSelectionDoSearch(saveAsDialog, NULL); XtManageChild(saveAsDialog); } void XPDFViewer::saveAsOkCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmFileSelectionBoxCallbackStruct *data = (XmFileSelectionBoxCallbackStruct *)callData; char *fileName; GString *fileNameStr; XmStringContext context; XmStringCharSet charSet; XmStringDirection dir; Boolean sep; XmStringInitContext(&context, data->value); if (XmStringGetNextSegment(context, &fileName, &charSet, &dir, &sep)) { fileNameStr = new GString(fileName); viewer->core->getDoc()->saveAs(fileNameStr); delete fileNameStr; XtFree(charSet); XtFree(fileName); } XmStringFreeContext(context); } //------------------------------------------------------------------------ // GUI code: "print" dialog //------------------------------------------------------------------------ void XPDFViewer::initPrintDialog() { Widget sep1, sep2, row, label1, label2, okBtn, cancelBtn; Arg args[20]; int n; XmString s; GString *psFileName; //----- dialog n = 0; s = XmStringCreateLocalized(xpdfAppName ": Print"); XtSetArg(args[n], XmNdialogTitle, s); ++n; XtSetArg(args[n], XmNdialogStyle, XmDIALOG_PRIMARY_APPLICATION_MODAL); ++n; printDialog = XmCreateFormDialog(win, "printDialog", args, n); XmStringFree(s); //----- "print with command" n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNtopOffset, 4); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); ++n; XtSetArg(args[n], XmNset, XmSET); ++n; s = XmStringCreateLocalized("Print with command:"); XtSetArg(args[n], XmNlabelString, s); ++n; printWithCmdBtn = XmCreateToggleButton(printDialog, "printWithCmd", args, n); XmStringFree(s); XtManageChild(printWithCmdBtn); XtAddCallback(printWithCmdBtn, XmNvalueChangedCallback, &printWithCmdBtnCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, printWithCmdBtn); ++n; XtSetArg(args[n], XmNtopOffset, 2); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 16); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNcolumns, 40); ++n; printCmdText = XmCreateTextField(printDialog, "printCmd", args, n); XtManageChild(printCmdText); //----- "print to file" n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, printCmdText); ++n; XtSetArg(args[n], XmNtopOffset, 4); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); ++n; XtSetArg(args[n], XmNset, XmUNSET); ++n; s = XmStringCreateLocalized("Print to file:"); XtSetArg(args[n], XmNlabelString, s); ++n; printToFileBtn = XmCreateToggleButton(printDialog, "printToFile", args, n); XmStringFree(s); XtManageChild(printToFileBtn); XtAddCallback(printToFileBtn, XmNvalueChangedCallback, &printToFileBtnCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, printToFileBtn); ++n; XtSetArg(args[n], XmNtopOffset, 2); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 16); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNcolumns, 40); ++n; XtSetArg(args[n], XmNsensitive, False); ++n; printFileText = XmCreateTextField(printDialog, "printFile", args, n); XtManageChild(printFileText); //----- separator n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, printFileText); ++n; XtSetArg(args[n], XmNtopOffset, 8); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 8); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 8); ++n; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; sep1 = XmCreateSeparator(printDialog, "sep1", args, n); XtManageChild(sep1); //----- page range n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, sep1); ++n; XtSetArg(args[n], XmNtopOffset, 8); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; XtSetArg(args[n], XmNpacking, XmPACK_TIGHT); ++n; row = XmCreateRowColumn(printDialog, "row", args, n); XtManageChild(row); n = 0; s = XmStringCreateLocalized("Pages:"); XtSetArg(args[n], XmNlabelString, s); ++n; label1 = XmCreateLabel(row, "label1", args, n); XmStringFree(s); XtManageChild(label1); n = 0; XtSetArg(args[n], XmNcolumns, 5); ++n; printFirstPage = XmCreateTextField(row, "printFirstPage", args, n); XtManageChild(printFirstPage); n = 0; s = XmStringCreateLocalized("to"); XtSetArg(args[n], XmNlabelString, s); ++n; label2 = XmCreateLabel(row, "label2", args, n); XmStringFree(s); XtManageChild(label2); n = 0; XtSetArg(args[n], XmNcolumns, 5); ++n; printLastPage = XmCreateTextField(row, "printLastPage", args, n); XtManageChild(printLastPage); //----- separator n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, row); ++n; XtSetArg(args[n], XmNtopOffset, 8); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 8); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 8); ++n; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); ++n; sep2 = XmCreateSeparator(printDialog, "sep2", args, n); XtManageChild(sep2); //----- "print" and "cancel" buttons n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, sep2); ++n; XtSetArg(args[n], XmNtopOffset, 8); ++n; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNleftOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; okBtn = XmCreatePushButton(printDialog, "Print", args, n); XtManageChild(okBtn); XtAddCallback(okBtn, XmNactivateCallback, &printPrintCbk, (XtPointer)this); n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); ++n; XtSetArg(args[n], XmNtopWidget, sep2); ++n; XtSetArg(args[n], XmNtopOffset, 8); ++n; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNrightOffset, 4); ++n; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); ++n; XtSetArg(args[n], XmNbottomOffset, 4); ++n; cancelBtn = XmCreatePushButton(printDialog, "Cancel", args, n); XtManageChild(cancelBtn); n = 0; XtSetArg(args[n], XmNdefaultButton, okBtn); ++n; XtSetArg(args[n], XmNcancelButton, cancelBtn); ++n; XtSetValues(printDialog, args, n); //----- initial values if ((psFileName = globalParams->getPSFile())) { if (psFileName->getChar(0) == '|') { XmTextFieldSetString(printCmdText, psFileName->getCString() + 1); } else { XmTextFieldSetString(printFileText, psFileName->getCString()); } delete psFileName; } } void XPDFViewer::setupPrintDialog() { PDFDoc *doc; char buf[20]; GString *pdfFileName, *psFileName, *psFileName2; char *p; doc = core->getDoc(); psFileName = globalParams->getPSFile(); if (!psFileName || psFileName->getChar(0) == '|') { pdfFileName = doc->getFileName(); p = pdfFileName->getCString() + pdfFileName->getLength() - 4; if (!strcmp(p, ".pdf") || !strcmp(p, ".PDF")) { psFileName2 = new GString(pdfFileName->getCString(), pdfFileName->getLength() - 4); } else { psFileName2 = pdfFileName->copy(); } psFileName2->append(".ps"); XmTextFieldSetString(printFileText, psFileName2->getCString()); delete psFileName2; } if (psFileName && psFileName->getChar(0) == '|') { XmToggleButtonSetState(printWithCmdBtn, True, False); XmToggleButtonSetState(printToFileBtn, False, False); XtVaSetValues(printCmdText, XmNsensitive, True, NULL); XtVaSetValues(printFileText, XmNsensitive, False, NULL); } else { XmToggleButtonSetState(printWithCmdBtn, False, False); XmToggleButtonSetState(printToFileBtn, True, False); XtVaSetValues(printCmdText, XmNsensitive, False, NULL); XtVaSetValues(printFileText, XmNsensitive, True, NULL); } if (psFileName) { delete psFileName; } sprintf(buf, "%d", doc->getNumPages()); XmTextFieldSetString(printFirstPage, "1"); XmTextFieldSetString(printLastPage, buf); } void XPDFViewer::printWithCmdBtnCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmToggleButtonCallbackStruct *data = (XmToggleButtonCallbackStruct *)callData; if (data->set != XmSET) { XmToggleButtonSetState(viewer->printWithCmdBtn, True, False); } XmToggleButtonSetState(viewer->printToFileBtn, False, False); XtVaSetValues(viewer->printCmdText, XmNsensitive, True, NULL); XtVaSetValues(viewer->printFileText, XmNsensitive, False, NULL); } void XPDFViewer::printToFileBtnCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; XmToggleButtonCallbackStruct *data = (XmToggleButtonCallbackStruct *)callData; if (data->set != XmSET) { XmToggleButtonSetState(viewer->printToFileBtn, True, False); } XmToggleButtonSetState(viewer->printWithCmdBtn, False, False); XtVaSetValues(viewer->printFileText, XmNsensitive, True, NULL); XtVaSetValues(viewer->printCmdText, XmNsensitive, False, NULL); } void XPDFViewer::printPrintCbk(Widget widget, XtPointer ptr, XtPointer callData) { XPDFViewer *viewer = (XPDFViewer *)ptr; unsigned char withCmd; GString *psFileName; int firstPage, lastPage; PDFDoc *doc; PSOutputDev *psOut; doc = viewer->core->getDoc(); if (!doc->okToPrint()) { error(errNotAllowed, -1, "Printing this document is not allowed."); return; } viewer->core->setBusyCursor(gTrue); XtVaGetValues(viewer->printWithCmdBtn, XmNset, &withCmd, NULL); if (withCmd) { psFileName = new GString(XmTextFieldGetString(viewer->printCmdText)); psFileName->insert(0, '|'); } else { psFileName = new GString(XmTextFieldGetString(viewer->printFileText)); } firstPage = atoi(XmTextFieldGetString(viewer->printFirstPage)); lastPage = atoi(XmTextFieldGetString(viewer->printLastPage)); if (firstPage < 1) { firstPage = 1; } else if (firstPage > doc->getNumPages()) { firstPage = doc->getNumPages(); } if (lastPage < firstPage) { lastPage = firstPage; } else if (lastPage > doc->getNumPages()) { lastPage = doc->getNumPages(); } psOut = new PSOutputDev(psFileName->getCString(), doc, firstPage, lastPage, psModePS); if (psOut->isOk()) { doc->displayPages(psOut, firstPage, lastPage, 72, 72, 0, gTrue, globalParams->getPSCrop(), gTrue); } delete psOut; delete psFileName; viewer->core->setBusyCursor(gFalse); } //------------------------------------------------------------------------ // Motif support //------------------------------------------------------------------------ XmFontList XPDFViewer::createFontList(char *xlfd) { XmFontList fontList; #if XmVersion <= 1001 XFontStruct *font; String params; Cardinal nParams; font = XLoadQueryFont(display, xlfd); if (font) { fontList = XmFontListCreate(font, XmSTRING_DEFAULT_CHARSET); } else { params = (String)xlfd; nParams = 1; XtAppWarningMsg(app->getAppContext(), "noSuchFont", "CvtStringToXmFontList", "XtToolkitError", "No such font: %s", ¶ms, &nParams); fontList = NULL; } #else XmFontListEntry entry; entry = XmFontListEntryLoad(display, xlfd, XmFONT_IS_FONT, XmFONTLIST_DEFAULT_TAG); fontList = XmFontListAppendEntry(NULL, entry); XmFontListEntryFree(&entry); #endif return fontList; } xpdf-3.03/xpdf/ErrorCodes.h0000644000076400007640000000173011622305345015075 0ustar dereknderekn//======================================================================== // // ErrorCodes.h // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef ERRORCODES_H #define ERRORCODES_H #define errNone 0 // no error #define errOpenFile 1 // couldn't open the PDF file #define errBadCatalog 2 // couldn't read the page catalog #define errDamaged 3 // PDF file was damaged and couldn't be // repaired #define errEncrypted 4 // file was encrypted and password was // incorrect or not supplied #define errHighlightFile 5 // nonexistent or invalid highlight file #define errBadPrinter 6 // invalid printer #define errPrinting 7 // error during printing #define errPermission 8 // PDF file doesn't allow that operation #define errBadPageNum 9 // invalid page number #define errFileIO 10 // file I/O error #endif xpdf-3.03/xpdf/BuiltinFont.h0000644000076400007640000000204211622305345015260 0ustar dereknderekn//======================================================================== // // BuiltinFont.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef BUILTINFONT_H #define BUILTINFONT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" struct BuiltinFont; class BuiltinFontWidths; //------------------------------------------------------------------------ struct BuiltinFont { const char *name; const char **defaultBaseEnc; short ascent; short descent; short bbox[4]; BuiltinFontWidths *widths; }; //------------------------------------------------------------------------ struct BuiltinFontWidth { const char *name; Gushort width; BuiltinFontWidth *next; }; class BuiltinFontWidths { public: BuiltinFontWidths(BuiltinFontWidth *widths, int sizeA); ~BuiltinFontWidths(); GBool getWidth(const char *name, Gushort *width); private: int hash(const char *name); BuiltinFontWidth **tab; int size; }; #endif xpdf-3.03/xpdf/Catalog.cc0000644000076400007640000004224311622305345014542 0ustar dereknderekn//======================================================================== // // Catalog.cc // // Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gmem.h" #include "gfile.h" #include "GList.h" #include "Object.h" #include "CharTypes.h" #include "PDFDoc.h" #include "XRef.h" #include "Array.h" #include "Dict.h" #include "Page.h" #include "Error.h" #include "Link.h" #include "PDFDocEncoding.h" #include "Catalog.h" //------------------------------------------------------------------------ // PageTreeNode //------------------------------------------------------------------------ class PageTreeNode { public: PageTreeNode(Ref refA, int countA, PageTreeNode *parentA); ~PageTreeNode(); Ref ref; int count; PageTreeNode *parent; GList *kids; // [PageTreeNode] PageAttrs *attrs; }; PageTreeNode::PageTreeNode(Ref refA, int countA, PageTreeNode *parentA) { ref = refA; count = countA; parent = parentA; kids = NULL; attrs = NULL; } PageTreeNode::~PageTreeNode() { delete attrs; if (kids) { deleteGList(kids, PageTreeNode); } } //------------------------------------------------------------------------ // EmbeddedFile //------------------------------------------------------------------------ class EmbeddedFile { public: EmbeddedFile(Unicode *nameA, int nameLenA, Object *streamRefA); ~EmbeddedFile(); Unicode *name; int nameLen; Object streamRef; }; EmbeddedFile::EmbeddedFile(Unicode *nameA, int nameLenA, Object *streamRefA) { name = nameA; nameLen = nameLenA; streamRefA->copy(&streamRef); } EmbeddedFile::~EmbeddedFile() { gfree(name); streamRef.free(); } //------------------------------------------------------------------------ // Catalog //------------------------------------------------------------------------ Catalog::Catalog(PDFDoc *docA) { Object catDict; Object obj, obj2; ok = gTrue; doc = docA; xref = doc->getXRef(); pageTree = NULL; pages = NULL; pageRefs = NULL; numPages = 0; baseURI = NULL; embeddedFiles = NULL; xref->getCatalog(&catDict); if (!catDict.isDict()) { error(errSyntaxError, -1, "Catalog object is wrong type ({0:s})", catDict.getTypeName()); goto err1; } // read page tree if (!readPageTree(&catDict)) { goto err1; } // read named destination dictionary catDict.dictLookup("Dests", &dests); // read root of named destination tree if (catDict.dictLookup("Names", &obj)->isDict()) obj.dictLookup("Dests", &nameTree); else nameTree.initNull(); obj.free(); // read base URI if (catDict.dictLookup("URI", &obj)->isDict()) { if (obj.dictLookup("Base", &obj2)->isString()) { baseURI = obj2.getString()->copy(); } obj2.free(); } obj.free(); if (!baseURI || baseURI->getLength() == 0) { if (baseURI) { delete baseURI; } if (doc->getFileName()) { baseURI = makePathAbsolute(grabPath(doc->getFileName()->getCString())); if (baseURI->getChar(0) == '/') { baseURI->insert(0, "file://localhost"); } else { baseURI->insert(0, "file://localhost/"); } } else { baseURI = new GString("file://localhost/"); } } // get the metadata stream catDict.dictLookup("Metadata", &metadata); // get the structure tree root catDict.dictLookup("StructTreeRoot", &structTreeRoot); // get the outline dictionary catDict.dictLookup("Outlines", &outline); // get the AcroForm dictionary catDict.dictLookup("AcroForm", &acroForm); // get the OCProperties dictionary catDict.dictLookup("OCProperties", &ocProperties); // get the list of embedded files readEmbeddedFileList(catDict.getDict()); catDict.free(); return; err1: catDict.free(); dests.initNull(); nameTree.initNull(); ok = gFalse; } Catalog::~Catalog() { int i; if (pageTree) { delete pageTree; } if (pages) { for (i = 0; i < numPages; ++i) { if (pages[i]) { delete pages[i]; } } gfree(pages); gfree(pageRefs); } dests.free(); nameTree.free(); if (baseURI) { delete baseURI; } metadata.free(); structTreeRoot.free(); outline.free(); acroForm.free(); ocProperties.free(); if (embeddedFiles) { deleteGList(embeddedFiles, EmbeddedFile); } } Page *Catalog::getPage(int i) { if (!pages[i-1]) { loadPage(i); } return pages[i-1]; } Ref *Catalog::getPageRef(int i) { if (!pages[i-1]) { loadPage(i); } return &pageRefs[i-1]; } void Catalog::doneWithPage(int i) { if (pages[i-1]) { delete pages[i-1]; pages[i-1] = NULL; } } GString *Catalog::readMetadata() { GString *s; Dict *dict; Object obj; int c; if (!metadata.isStream()) { return NULL; } dict = metadata.streamGetDict(); if (!dict->lookup("Subtype", &obj)->isName("XML")) { error(errSyntaxWarning, -1, "Unknown Metadata type: '{0:s}'", obj.isName() ? obj.getName() : "???"); } obj.free(); s = new GString(); metadata.streamReset(); while ((c = metadata.streamGetChar()) != EOF) { s->append(c); } metadata.streamClose(); return s; } int Catalog::findPage(int num, int gen) { int i; for (i = 0; i < numPages; ++i) { if (!pages[i]) { loadPage(i+1); } if (pageRefs[i].num == num && pageRefs[i].gen == gen) return i + 1; } return 0; } LinkDest *Catalog::findDest(GString *name) { LinkDest *dest; Object obj1, obj2; GBool found; // try named destination dictionary then name tree found = gFalse; if (dests.isDict()) { if (!dests.dictLookup(name->getCString(), &obj1)->isNull()) found = gTrue; else obj1.free(); } if (!found && nameTree.isDict()) { if (!findDestInTree(&nameTree, name, &obj1)->isNull()) found = gTrue; else obj1.free(); } if (!found) return NULL; // construct LinkDest dest = NULL; if (obj1.isArray()) { dest = new LinkDest(obj1.getArray()); } else if (obj1.isDict()) { if (obj1.dictLookup("D", &obj2)->isArray()) dest = new LinkDest(obj2.getArray()); else error(errSyntaxWarning, -1, "Bad named destination value"); obj2.free(); } else { error(errSyntaxWarning, -1, "Bad named destination value"); } obj1.free(); if (dest && !dest->isOk()) { delete dest; dest = NULL; } return dest; } Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) { Object names, name1; Object kids, kid, limits, low, high; GBool done, found; int cmp, i; // leaf node if (tree->dictLookup("Names", &names)->isArray()) { done = found = gFalse; for (i = 0; !done && i < names.arrayGetLength(); i += 2) { if (names.arrayGet(i, &name1)->isString()) { cmp = name->cmp(name1.getString()); if (cmp == 0) { names.arrayGet(i+1, obj); found = gTrue; done = gTrue; } else if (cmp < 0) { done = gTrue; } } name1.free(); } names.free(); if (!found) obj->initNull(); return obj; } names.free(); // root or intermediate node done = gFalse; if (tree->dictLookup("Kids", &kids)->isArray()) { for (i = 0; !done && i < kids.arrayGetLength(); ++i) { if (kids.arrayGet(i, &kid)->isDict()) { if (kid.dictLookup("Limits", &limits)->isArray()) { if (limits.arrayGet(0, &low)->isString() && name->cmp(low.getString()) >= 0) { if (limits.arrayGet(1, &high)->isString() && name->cmp(high.getString()) <= 0) { findDestInTree(&kid, name, obj); done = gTrue; } high.free(); } low.free(); } limits.free(); } kid.free(); } } kids.free(); // name was outside of ranges of all kids if (!done) obj->initNull(); return obj; } GBool Catalog::readPageTree(Object *catDict) { Object topPagesRef, topPagesObj, countObj; int i; if (!catDict->dictLookupNF("Pages", &topPagesRef)->isRef()) { error(errSyntaxError, -1, "Top-level pages reference is wrong type ({0:s})", topPagesRef.getTypeName()); topPagesRef.free(); return gFalse; } if (!topPagesRef.fetch(xref, &topPagesObj)->isDict()) { error(errSyntaxError, -1, "Top-level pages object is wrong type ({0:s})", topPagesObj.getTypeName()); topPagesObj.free(); topPagesRef.free(); return gFalse; } if (topPagesObj.dictLookup("Count", &countObj)->isInt()) { numPages = countObj.getInt(); if (numPages == 0) { // Acrobat apparently scans the page tree if it sees a zero count numPages = countPageTree(&topPagesObj); } } else { // assume we got a Page node instead of a Pages node numPages = 1; } countObj.free(); if (numPages < 0) { error(errSyntaxError, -1, "Invalid page count"); topPagesObj.free(); topPagesRef.free(); numPages = 0; return gFalse; } pageTree = new PageTreeNode(topPagesRef.getRef(), numPages, NULL); topPagesObj.free(); topPagesRef.free(); pages = (Page **)greallocn(pages, numPages, sizeof(Page *)); pageRefs = (Ref *)greallocn(pageRefs, numPages, sizeof(Ref)); for (i = 0; i < numPages; ++i) { pages[i] = NULL; pageRefs[i].num = -1; pageRefs[i].gen = -1; } return gTrue; } int Catalog::countPageTree(Object *pagesObj) { Object kids, kid; int n, n2, i; if (!pagesObj->isDict()) { return 0; } if (pagesObj->dictLookup("Kids", &kids)->isArray()) { n = 0; for (i = 0; i < kids.arrayGetLength(); ++i) { kids.arrayGet(i, &kid); n2 = countPageTree(&kid); if (n2 < INT_MAX - n) { n += n2; } else { error(errSyntaxError, -1, "Page tree contains too many pages"); n = INT_MAX; } kid.free(); } } else { n = 1; } kids.free(); return n; } void Catalog::loadPage(int pg) { loadPage2(pg, pg - 1, pageTree); } void Catalog::loadPage2(int pg, int relPg, PageTreeNode *node) { Object pageRefObj, pageObj, kidsObj, kidRefObj, kidObj, countObj; PageTreeNode *kidNode, *p; PageAttrs *attrs; int count, i; if (relPg >= node->count) { error(errSyntaxError, -1, "Internal error in page tree"); pages[pg-1] = new Page(doc, pg); return; } // if this node has not been filled in yet, it's either a leaf node // or an unread internal node if (!node->kids) { // check for a loop in the page tree for (p = node->parent; p; p = p->parent) { if (node->ref.num == p->ref.num && node->ref.gen == p->ref.gen) { error(errSyntaxError, -1, "Loop in Pages tree"); pages[pg-1] = new Page(doc, pg); return; } } // fetch the Page/Pages object pageRefObj.initRef(node->ref.num, node->ref.gen); if (!pageRefObj.fetch(xref, &pageObj)->isDict()) { error(errSyntaxError, -1, "Page tree object is wrong type ({0:s})", pageObj.getTypeName()); pageObj.free(); pageRefObj.free(); pages[pg-1] = new Page(doc, pg); return; } // merge the PageAttrs attrs = new PageAttrs(node->parent ? node->parent->attrs : (PageAttrs *)NULL, pageObj.getDict()); // if "Kids" exists, it's an internal node if (pageObj.dictLookup("Kids", &kidsObj)->isArray()) { // save the PageAttrs node->attrs = attrs; // read the kids node->kids = new GList(); for (i = 0; i < kidsObj.arrayGetLength(); ++i) { if (kidsObj.arrayGetNF(i, &kidRefObj)->isRef()) { if (kidRefObj.fetch(xref, &kidObj)->isDict()) { if (kidObj.dictLookup("Count", &countObj)->isInt()) { count = countObj.getInt(); } else { count = 1; } countObj.free(); node->kids->append(new PageTreeNode(kidRefObj.getRef(), count, node)); } else { error(errSyntaxError, -1, "Page tree object is wrong type ({0:s})", kidObj.getTypeName()); } kidObj.free(); } else { error(errSyntaxError, -1, "Page tree reference is wrong type ({0:s})", kidRefObj.getTypeName()); } kidRefObj.free(); } } else { // create the Page object pageRefs[pg-1] = node->ref; pages[pg-1] = new Page(doc, pg, pageObj.getDict(), attrs); if (!pages[pg-1]->isOk()) { delete pages[pg-1]; pages[pg-1] = new Page(doc, pg); } } kidsObj.free(); pageObj.free(); pageRefObj.free(); } // recursively descend the tree if (node->kids) { for (i = 0; i < node->kids->getLength(); ++i) { kidNode = (PageTreeNode *)node->kids->get(i); if (relPg < kidNode->count) { loadPage2(pg, relPg, kidNode); break; } relPg -= kidNode->count; } // this will only happen if the page tree is invalid // (i.e., parent count > sum of children counts) if (i == node->kids->getLength()) { error(errSyntaxError, -1, "Invalid page count in page tree"); pages[pg-1] = new Page(doc, pg); } } } void Catalog::readEmbeddedFileList(Dict *catDict) { Object obj1, obj2; char *touchedObjs; // read the embedded file name tree if (catDict->lookup("Names", &obj1)->isDict()) { if (obj1.dictLookup("EmbeddedFiles", &obj2)->isDict()) { readEmbeddedFileTree(&obj2); } obj2.free(); } obj1.free(); // look for file attachment annotations touchedObjs = (char *)gmalloc(xref->getNumObjects()); memset(touchedObjs, 0, xref->getNumObjects()); readFileAttachmentAnnots(catDict->lookupNF("Pages", &obj1), touchedObjs); obj1.free(); gfree(touchedObjs); } void Catalog::readEmbeddedFileTree(Object *node) { Object kidsObj, kidObj; Object namesObj, nameObj, fileSpecObj; int i; if (node->dictLookup("Kids", &kidsObj)->isArray()) { for (i = 0; i < kidsObj.arrayGetLength(); ++i) { if (kidsObj.arrayGet(i, &kidObj)->isDict()) { readEmbeddedFileTree(&kidObj); } kidObj.free(); } } else { if (node->dictLookup("Names", &namesObj)->isArray()) { for (i = 0; i+1 < namesObj.arrayGetLength(); ++i) { namesObj.arrayGet(i, &nameObj); namesObj.arrayGet(i+1, &fileSpecObj); readEmbeddedFile(&fileSpecObj, &nameObj); nameObj.free(); fileSpecObj.free(); } } namesObj.free(); } kidsObj.free(); } void Catalog::readFileAttachmentAnnots(Object *pageNodeRef, char *touchedObjs) { Object pageNode, kids, kid, annots, annot, subtype, fileSpec, contents; int i; // check for a page tree loop if (pageNodeRef->isRef()) { if (touchedObjs[pageNodeRef->getRefNum()]) { return; } touchedObjs[pageNodeRef->getRefNum()] = 1; xref->fetch(pageNodeRef->getRefNum(), pageNodeRef->getRefGen(), &pageNode); } else { pageNodeRef->copy(&pageNode); } if (pageNode.isDict()) { if (pageNode.dictLookup("Kids", &kids)->isArray()) { for (i = 0; i < kids.arrayGetLength(); ++i) { readFileAttachmentAnnots(kids.arrayGetNF(i, &kid), touchedObjs); kid.free(); } } else { if (pageNode.dictLookup("Annots", &annots)->isArray()) { for (i = 0; i < annots.arrayGetLength(); ++i) { if (annots.arrayGet(i, &annot)->isDict()) { if (annot.dictLookup("Subtype", &subtype) ->isName("FileAttachment")) { if (annot.dictLookup("FS", &fileSpec)) { readEmbeddedFile(&fileSpec, annot.dictLookup("Contents", &contents)); contents.free(); } fileSpec.free(); } subtype.free(); } annot.free(); } } annots.free(); } kids.free(); } pageNode.free(); } void Catalog::readEmbeddedFile(Object *fileSpec, Object *name1) { Object name2, efObj, streamObj; GString *s; Unicode *name; int nameLen, i; if (fileSpec->isDict()) { if (fileSpec->dictLookup("UF", &name2)->isString()) { s = name2.getString(); } else { name2.free(); if (fileSpec->dictLookup("F", &name2)->isString()) { s = name2.getString(); } else if (name1 && name1->isString()) { s = name1->getString(); } else { s = NULL; } } if (s) { if ((s->getChar(0) & 0xff) == 0xfe && (s->getChar(1) & 0xff) == 0xff) { nameLen = (s->getLength() - 2) / 2; name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); for (i = 0; i < nameLen; ++i) { name[i] = ((s->getChar(2 + 2*i) & 0xff) << 8) | (s->getChar(3 + 2*i) & 0xff); } } else { nameLen = s->getLength(); name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); for (i = 0; i < nameLen; ++i) { name[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } } } else { nameLen = 1; name = (Unicode *)gmallocn(nameLen, sizeof(Unicode)); name[0] = '?'; } name2.free(); if (fileSpec->dictLookup("EF", &efObj)->isDict()) { if (efObj.dictLookupNF("F", &streamObj)->isRef()) { if (!embeddedFiles) { embeddedFiles = new GList(); } embeddedFiles->append(new EmbeddedFile(name, nameLen, &streamObj)); } else { gfree(name); } streamObj.free(); } else { gfree(name); } efObj.free(); } } int Catalog::getNumEmbeddedFiles() { return embeddedFiles ? embeddedFiles->getLength() : 0; } Unicode *Catalog::getEmbeddedFileName(int idx) { return ((EmbeddedFile *)embeddedFiles->get(idx))->name; } int Catalog::getEmbeddedFileNameLength(int idx) { return ((EmbeddedFile *)embeddedFiles->get(idx))->nameLen; } Object *Catalog::getEmbeddedFileStreamObj(int idx, Object *strObj) { ((EmbeddedFile *)embeddedFiles->get(idx))->streamRef.fetch(xref, strObj); if (!strObj->isStream()) { strObj->free(); return NULL; } return strObj; } xpdf-3.03/xpdf/PreScanOutputDev.h0000644000076400007640000001170211622305345016241 0ustar dereknderekn//======================================================================== // // PreScanOutputDev.h // // Copyright 2005 Glyph & Cog, LLC // //======================================================================== #ifndef PRESCANOUTPUTDEV_H #define PRESCANOUTPUTDEV_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "GfxState.h" #include "OutputDev.h" //------------------------------------------------------------------------ // PreScanOutputDev //------------------------------------------------------------------------ class PreScanOutputDev: public OutputDev { public: // Constructor. PreScanOutputDev(); // Destructor. virtual ~PreScanOutputDev(); //----- get info about output device // Does this device use upside-down coordinates? // (Upside-down means (0,0) is the top left corner of the page.) virtual GBool upsideDown() { return gTrue; } // Does this device use drawChar() or drawString()? virtual GBool useDrawChar() { return gTrue; } // Does this device use tilingPatternFill()? If this returns false, // tiling pattern fills will be reduced to a series of other drawing // operations. virtual GBool useTilingPatternFill() { return gTrue; } // Does this device use functionShadedFill(), axialShadedFill(), and // radialShadedFill()? If this returns false, these shaded fills // will be reduced to a series of other drawing operations. virtual GBool useShadedFills() { return gTrue; } // Does this device use beginType3Char/endType3Char? Otherwise, // text in Type 3 fonts will be drawn with drawChar/drawString. virtual GBool interpretType3Chars() { return gTrue; } //----- initialization and control // Start a page. virtual void startPage(int pageNum, GfxState *state); // End a page. virtual void endPage(); //----- path painting virtual void stroke(GfxState *state); virtual void fill(GfxState *state); virtual void eoFill(GfxState *state); virtual void tilingPatternFill(GfxState *state, Gfx *gfx, Object *str, int paintType, Dict *resDict, double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep); virtual GBool functionShadedFill(GfxState *state, GfxFunctionShading *shading); virtual GBool axialShadedFill(GfxState *state, GfxAxialShading *shading); virtual GBool radialShadedFill(GfxState *state, GfxRadialShading *shading); //----- path clipping virtual void clip(GfxState *state); virtual void eoClip(GfxState *state); //----- text drawing virtual void beginStringOp(GfxState *state); virtual void endStringOp(GfxState *state); virtual GBool beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state); //----- image drawing virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg); virtual void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg); virtual void drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert); virtual void drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap); //----- transparency groups and soft masks virtual void beginTransparencyGroup(GfxState *state, double *bbox, GfxColorSpace *blendingColorSpace, GBool isolated, GBool knockout, GBool forSoftMask); //----- special access // Returns true if the operations performed since the last call to // clearStats() are all monochrome (black or white). GBool isMonochrome() { return mono; } // Returns true if the operations performed since the last call to // clearStats() are all gray. GBool isGray() { return gray; } // Returns true if the operations performed since the last call to // clearStats() included any transparency. GBool usesTransparency() { return transparency; } // Returns true if the operations performed since the last call to // clearStats() included any image mask fills with a pattern color // space. GBool usesPatternImageMask() { return patternImgMask; } // Returns true if the operations performed since the last call to // clearStats() are all rasterizable by GDI calls in GDIOutputDev. GBool isAllGDI() { return gdi; } // Clear the stats used by the above functions. void clearStats(); private: void check(GfxColorSpace *colorSpace, GfxColor *color, double opacity, GfxBlendMode blendMode); GBool mono; GBool gray; GBool transparency; GBool patternImgMask; GBool gdi; }; #endif xpdf-3.03/xpdf/Object.cc0000644000076400007640000001013011622305345014364 0ustar dereknderekn//======================================================================== // // Object.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "Object.h" #include "Array.h" #include "Dict.h" #include "Error.h" #include "Stream.h" #include "XRef.h" //------------------------------------------------------------------------ // Object //------------------------------------------------------------------------ const char *objTypeNames[numObjTypes] = { "boolean", "integer", "real", "string", "name", "null", "array", "dictionary", "stream", "ref", "cmd", "error", "eof", "none" }; #ifdef DEBUG_MEM int Object::numAlloc[numObjTypes] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; #endif Object *Object::initArray(XRef *xref) { initObj(objArray); array = new Array(xref); return this; } Object *Object::initDict(XRef *xref) { initObj(objDict); dict = new Dict(xref); return this; } Object *Object::initDict(Dict *dictA) { initObj(objDict); dict = dictA; dict->incRef(); return this; } Object *Object::initStream(Stream *streamA) { initObj(objStream); stream = streamA; return this; } Object *Object::copy(Object *obj) { *obj = *this; switch (type) { case objString: obj->string = string->copy(); break; case objName: obj->name = copyString(name); break; case objArray: array->incRef(); break; case objDict: dict->incRef(); break; case objStream: stream->incRef(); break; case objCmd: obj->cmd = copyString(cmd); break; default: break; } #ifdef DEBUG_MEM ++numAlloc[type]; #endif return obj; } Object *Object::fetch(XRef *xref, Object *obj, int recursion) { return (type == objRef && xref) ? xref->fetch(ref.num, ref.gen, obj, recursion) : copy(obj); } void Object::free() { switch (type) { case objString: delete string; break; case objName: gfree(name); break; case objArray: if (!array->decRef()) { delete array; } break; case objDict: if (!dict->decRef()) { delete dict; } break; case objStream: if (!stream->decRef()) { delete stream; } break; case objCmd: gfree(cmd); break; default: break; } #ifdef DEBUG_MEM --numAlloc[type]; #endif type = objNone; } const char *Object::getTypeName() { return objTypeNames[type]; } void Object::print(FILE *f) { Object obj; int i; switch (type) { case objBool: fprintf(f, "%s", booln ? "true" : "false"); break; case objInt: fprintf(f, "%d", intg); break; case objReal: fprintf(f, "%g", real); break; case objString: fprintf(f, "("); fwrite(string->getCString(), 1, string->getLength(), f); fprintf(f, ")"); break; case objName: fprintf(f, "/%s", name); break; case objNull: fprintf(f, "null"); break; case objArray: fprintf(f, "["); for (i = 0; i < arrayGetLength(); ++i) { if (i > 0) fprintf(f, " "); arrayGetNF(i, &obj); obj.print(f); obj.free(); } fprintf(f, "]"); break; case objDict: fprintf(f, "<<"); for (i = 0; i < dictGetLength(); ++i) { fprintf(f, " /%s ", dictGetKey(i)); dictGetValNF(i, &obj); obj.print(f); obj.free(); } fprintf(f, " >>"); break; case objStream: fprintf(f, ""); break; case objRef: fprintf(f, "%d %d R", ref.num, ref.gen); break; case objCmd: fprintf(f, "%s", cmd); break; case objError: fprintf(f, ""); break; case objEOF: fprintf(f, ""); break; case objNone: fprintf(f, ""); break; } } void Object::memCheck(FILE *f) { #ifdef DEBUG_MEM int i; int t; t = 0; for (i = 0; i < numObjTypes; ++i) t += numAlloc[i]; if (t > 0) { fprintf(f, "Allocated objects:\n"); for (i = 0; i < numObjTypes; ++i) { if (numAlloc[i] > 0) fprintf(f, " %-20s: %6d\n", objTypeNames[i], numAlloc[i]); } } #endif } xpdf-3.03/xpdf/OutputDev.cc0000644000076400007640000000735411622305345015133 0ustar dereknderekn//======================================================================== // // OutputDev.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "Object.h" #include "Stream.h" #include "GfxState.h" #include "OutputDev.h" //------------------------------------------------------------------------ // OutputDev //------------------------------------------------------------------------ void OutputDev::setDefaultCTM(double *ctm) { int i; double det; for (i = 0; i < 6; ++i) { defCTM[i] = ctm[i]; } det = 1 / (defCTM[0] * defCTM[3] - defCTM[1] * defCTM[2]); defICTM[0] = defCTM[3] * det; defICTM[1] = -defCTM[1] * det; defICTM[2] = -defCTM[2] * det; defICTM[3] = defCTM[0] * det; defICTM[4] = (defCTM[2] * defCTM[5] - defCTM[3] * defCTM[4]) * det; defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det; } void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) { *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4]; *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5]; } void OutputDev::cvtUserToDev(double ux, double uy, int *dx, int *dy) { *dx = (int)(defCTM[0] * ux + defCTM[2] * uy + defCTM[4] + 0.5); *dy = (int)(defCTM[1] * ux + defCTM[3] * uy + defCTM[5] + 0.5); } void OutputDev::updateAll(GfxState *state) { updateLineDash(state); updateFlatness(state); updateLineJoin(state); updateLineCap(state); updateMiterLimit(state); updateLineWidth(state); updateStrokeAdjust(state); updateFillColorSpace(state); updateFillColor(state); updateStrokeColorSpace(state); updateStrokeColor(state); updateBlendMode(state); updateFillOpacity(state); updateStrokeOpacity(state); updateFillOverprint(state); updateStrokeOverprint(state); updateOverprintMode(state); updateTransfer(state); updateFont(state); } GBool OutputDev::beginType3Char(GfxState *state, double x, double y, double dx, double dy, CharCode code, Unicode *u, int uLen) { return gFalse; } void OutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { int i, j; if (inlineImg) { str->reset(); j = height * ((width + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); str->close(); } } void OutputDev::setSoftMaskFromImageMask(GfxState *state, Object *ref, Stream *str, int width, int height, GBool invert, GBool inlineImg) { drawImageMask(state, ref, str, width, height, invert, inlineImg); } void OutputDev::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, int *maskColors, GBool inlineImg) { int i, j; if (inlineImg) { str->reset(); j = height * ((width * colorMap->getNumPixelComps() * colorMap->getBits() + 7) / 8); for (i = 0; i < j; ++i) str->getChar(); str->close(); } } void OutputDev::drawMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GBool maskInvert) { drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); } void OutputDev::drawSoftMaskedImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, Stream *maskStr, int maskWidth, int maskHeight, GfxImageColorMap *maskColorMap) { drawImage(state, ref, str, width, height, colorMap, NULL, gFalse); } #if OPI_SUPPORT void OutputDev::opiBegin(GfxState *state, Dict *opiDict) { } void OutputDev::opiEnd(GfxState *state, Dict *opiDict) { } #endif xpdf-3.03/xpdf/JArithmeticDecoder.cc0000644000076400007640000001703411622305345016661 0ustar dereknderekn//======================================================================== // // JArithmeticDecoder.cc // // Copyright 2002-2004 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "Object.h" #include "Stream.h" #include "JArithmeticDecoder.h" //------------------------------------------------------------------------ // JArithmeticDecoderStates //------------------------------------------------------------------------ JArithmeticDecoderStats::JArithmeticDecoderStats(int contextSizeA) { contextSize = contextSizeA; cxTab = (Guchar *)gmallocn(contextSize, sizeof(Guchar)); reset(); } JArithmeticDecoderStats::~JArithmeticDecoderStats() { gfree(cxTab); } JArithmeticDecoderStats *JArithmeticDecoderStats::copy() { JArithmeticDecoderStats *stats; stats = new JArithmeticDecoderStats(contextSize); memcpy(stats->cxTab, cxTab, contextSize); return stats; } void JArithmeticDecoderStats::reset() { memset(cxTab, 0, contextSize); } void JArithmeticDecoderStats::copyFrom(JArithmeticDecoderStats *stats) { memcpy(cxTab, stats->cxTab, contextSize); } void JArithmeticDecoderStats::setEntry(Guint cx, int i, int mps) { cxTab[cx] = (i << 1) + mps; } //------------------------------------------------------------------------ // JArithmeticDecoder //------------------------------------------------------------------------ Guint JArithmeticDecoder::qeTab[47] = { 0x56010000, 0x34010000, 0x18010000, 0x0AC10000, 0x05210000, 0x02210000, 0x56010000, 0x54010000, 0x48010000, 0x38010000, 0x30010000, 0x24010000, 0x1C010000, 0x16010000, 0x56010000, 0x54010000, 0x51010000, 0x48010000, 0x38010000, 0x34010000, 0x30010000, 0x28010000, 0x24010000, 0x22010000, 0x1C010000, 0x18010000, 0x16010000, 0x14010000, 0x12010000, 0x11010000, 0x0AC10000, 0x09C10000, 0x08A10000, 0x05210000, 0x04410000, 0x02A10000, 0x02210000, 0x01410000, 0x01110000, 0x00850000, 0x00490000, 0x00250000, 0x00150000, 0x00090000, 0x00050000, 0x00010000, 0x56010000 }; int JArithmeticDecoder::nmpsTab[47] = { 1, 2, 3, 4, 5, 38, 7, 8, 9, 10, 11, 12, 13, 29, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 45, 46 }; int JArithmeticDecoder::nlpsTab[47] = { 1, 6, 9, 12, 29, 33, 6, 14, 14, 14, 17, 18, 20, 21, 14, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 46 }; int JArithmeticDecoder::switchTab[47] = { 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 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 }; JArithmeticDecoder::JArithmeticDecoder() { str = NULL; dataLen = 0; limitStream = gFalse; nBytesRead = 0; } inline Guint JArithmeticDecoder::readByte() { if (limitStream) { --dataLen; if (dataLen < 0) { return 0xff; } } ++nBytesRead; return (Guint)str->getChar() & 0xff; } JArithmeticDecoder::~JArithmeticDecoder() { cleanup(); } void JArithmeticDecoder::start() { buf0 = readByte(); buf1 = readByte(); // INITDEC c = (buf0 ^ 0xff) << 16; byteIn(); c <<= 7; ct -= 7; a = 0x80000000; } void JArithmeticDecoder::restart(int dataLenA) { Guint cAdd; GBool prevFF; int k, nBits; if (dataLen >= 0) { dataLen = dataLenA; } else if (dataLen == -1) { dataLen = dataLenA; buf1 = readByte(); } else { k = (-dataLen - 1) * 8 - ct; dataLen = dataLenA; cAdd = 0; prevFF = gFalse; while (k > 0) { buf0 = readByte(); if (prevFF) { cAdd += 0xfe00 - (buf0 << 9); nBits = 7; } else { cAdd += 0xff00 - (buf0 << 8); nBits = 8; } prevFF = buf0 == 0xff; if (k > nBits) { cAdd <<= nBits; k -= nBits; } else { cAdd <<= k; ct = nBits - k; k = 0; } } c += cAdd; buf1 = readByte(); } } void JArithmeticDecoder::cleanup() { if (limitStream) { while (dataLen > 0) { buf0 = buf1; buf1 = readByte(); } } } int JArithmeticDecoder::decodeBit(Guint context, JArithmeticDecoderStats *stats) { int bit; Guint qe; int iCX, mpsCX; iCX = stats->cxTab[context] >> 1; mpsCX = stats->cxTab[context] & 1; qe = qeTab[iCX]; a -= qe; if (c < a) { if (a & 0x80000000) { bit = mpsCX; } else { // MPS_EXCHANGE if (a < qe) { bit = 1 - mpsCX; if (switchTab[iCX]) { stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); } else { stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; } } else { bit = mpsCX; stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; } // RENORMD do { if (ct == 0) { byteIn(); } a <<= 1; c <<= 1; --ct; } while (!(a & 0x80000000)); } } else { c -= a; // LPS_EXCHANGE if (a < qe) { bit = mpsCX; stats->cxTab[context] = (nmpsTab[iCX] << 1) | mpsCX; } else { bit = 1 - mpsCX; if (switchTab[iCX]) { stats->cxTab[context] = (nlpsTab[iCX] << 1) | (1 - mpsCX); } else { stats->cxTab[context] = (nlpsTab[iCX] << 1) | mpsCX; } } a = qe; // RENORMD do { if (ct == 0) { byteIn(); } a <<= 1; c <<= 1; --ct; } while (!(a & 0x80000000)); } return bit; } int JArithmeticDecoder::decodeByte(Guint context, JArithmeticDecoderStats *stats) { int byte; int i; byte = 0; for (i = 0; i < 8; ++i) { byte = (byte << 1) | decodeBit(context, stats); } return byte; } GBool JArithmeticDecoder::decodeInt(int *x, JArithmeticDecoderStats *stats) { int s; Guint v; int i; prev = 1; s = decodeIntBit(stats); if (decodeIntBit(stats)) { if (decodeIntBit(stats)) { if (decodeIntBit(stats)) { if (decodeIntBit(stats)) { if (decodeIntBit(stats)) { v = 0; for (i = 0; i < 32; ++i) { v = (v << 1) | decodeIntBit(stats); } v += 4436; } else { v = 0; for (i = 0; i < 12; ++i) { v = (v << 1) | decodeIntBit(stats); } v += 340; } } else { v = 0; for (i = 0; i < 8; ++i) { v = (v << 1) | decodeIntBit(stats); } v += 84; } } else { v = 0; for (i = 0; i < 6; ++i) { v = (v << 1) | decodeIntBit(stats); } v += 20; } } else { v = decodeIntBit(stats); v = (v << 1) | decodeIntBit(stats); v = (v << 1) | decodeIntBit(stats); v = (v << 1) | decodeIntBit(stats); v += 4; } } else { v = decodeIntBit(stats); v = (v << 1) | decodeIntBit(stats); } if (s) { if (v == 0) { return gFalse; } *x = -(int)v; } else { *x = (int)v; } return gTrue; } int JArithmeticDecoder::decodeIntBit(JArithmeticDecoderStats *stats) { int bit; bit = decodeBit(prev, stats); if (prev < 0x100) { prev = (prev << 1) | bit; } else { prev = (((prev << 1) | bit) & 0x1ff) | 0x100; } return bit; } Guint JArithmeticDecoder::decodeIAID(Guint codeLen, JArithmeticDecoderStats *stats) { Guint i; int bit; prev = 1; for (i = 0; i < codeLen; ++i) { bit = decodeBit(prev, stats); prev = (prev << 1) | bit; } return prev - (1 << codeLen); } void JArithmeticDecoder::byteIn() { if (buf0 == 0xff) { if (buf1 > 0x8f) { if (limitStream) { buf0 = buf1; buf1 = readByte(); c = c + 0xff00 - (buf0 << 8); } ct = 8; } else { buf0 = buf1; buf1 = readByte(); c = c + 0xfe00 - (buf0 << 9); ct = 7; } } else { buf0 = buf1; buf1 = readByte(); c = c + 0xff00 - (buf0 << 8); ct = 8; } } xpdf-3.03/xpdf/printDis.xbm0000644000076400007640000000043411622305345015161 0ustar dereknderekn#define printDis_width 15 #define printDis_height 15 static unsigned char printDis_bits[] = { 0xa0, 0x2a, 0x10, 0x40, 0x00, 0x00, 0x40, 0x01, 0x08, 0x20, 0x40, 0x01, 0x00, 0x00, 0x14, 0x10, 0x00, 0x00, 0x55, 0x55, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x01, 0x40, 0xaa, 0x2a}; xpdf-3.03/xpdf/CharCodeToUnicode.cc0000644000076400007640000003604011622305345016450 0ustar dereknderekn//======================================================================== // // CharCodeToUnicode.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "gfile.h" #include "GString.h" #include "Error.h" #include "GlobalParams.h" #include "PSTokenizer.h" #include "CharCodeToUnicode.h" //------------------------------------------------------------------------ #define maxUnicodeString 8 struct CharCodeToUnicodeString { CharCode c; Unicode u[maxUnicodeString]; int len; }; //------------------------------------------------------------------------ static int getCharFromString(void *data) { char *p; int c; p = *(char **)data; if (*p) { c = *p++; *(char **)data = p; } else { c = EOF; } return c; } static int getCharFromFile(void *data) { return fgetc((FILE *)data); } //------------------------------------------------------------------------ static int hexCharVals[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 1x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 2x 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 3x -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 4x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 5x -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 6x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 7x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 8x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 9x -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ax -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Bx -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Cx -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Dx -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // Ex -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // Fx }; // Parse a -byte hex string into *. Returns false on // error. static GBool parseHex(char *s, int len, Guint *val) { int i, x; *val = 0; for (i = 0; i < len; ++i) { x = hexCharVals[s[i] & 0xff]; if (x < 0) { return gFalse; } *val = (*val << 4) + x; } return gTrue; } //------------------------------------------------------------------------ CharCodeToUnicode *CharCodeToUnicode::makeIdentityMapping() { return new CharCodeToUnicode(); } CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName, GString *collection) { FILE *f; Unicode *mapA; CharCode size, mapLenA; char buf[64]; Unicode u; CharCodeToUnicode *ctu; if (!(f = openFile(fileName->getCString(), "r"))) { error(errSyntaxError, -1, "Couldn't open cidToUnicode file '{0:t}'", fileName); return NULL; } size = 32768; mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); mapLenA = 0; while (getLine(buf, sizeof(buf), f)) { if (mapLenA == size) { size *= 2; mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); } if (sscanf(buf, "%x", &u) == 1) { mapA[mapLenA] = u; } else { error(errSyntaxWarning, -1, "Bad line ({0:d}) in cidToUnicode file '{1:t}'", (int)(mapLenA + 1), fileName); mapA[mapLenA] = 0; } ++mapLenA; } fclose(f); ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue, NULL, 0, 0); gfree(mapA); return ctu; } CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode( GString *fileName) { FILE *f; Unicode *mapA; CharCodeToUnicodeString *sMapA; CharCode size, oldSize, len, sMapSizeA, sMapLenA; char buf[256]; char *tok; Unicode u0; Unicode uBuf[maxUnicodeString]; CharCodeToUnicode *ctu; int line, n, i; if (!(f = openFile(fileName->getCString(), "r"))) { error(errSyntaxError, -1, "Couldn't open unicodeToUnicode file '{0:t}'", fileName); return NULL; } size = 4096; mapA = (Unicode *)gmallocn(size, sizeof(Unicode)); memset(mapA, 0, size * sizeof(Unicode)); len = 0; sMapA = NULL; sMapSizeA = sMapLenA = 0; line = 0; while (getLine(buf, sizeof(buf), f)) { ++line; if (!(tok = strtok(buf, " \t\r\n")) || !parseHex(tok, strlen(tok), &u0)) { error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'", line, fileName); continue; } n = 0; while (n < maxUnicodeString) { if (!(tok = strtok(NULL, " \t\r\n"))) { break; } if (!parseHex(tok, strlen(tok), &uBuf[n])) { error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'", line, fileName); break; } ++n; } if (n < 1) { error(errSyntaxWarning, -1, "Bad line ({0:d}) in unicodeToUnicode file '{1:t}'", line, fileName); continue; } if (u0 >= size) { oldSize = size; while (u0 >= size) { size *= 2; } mapA = (Unicode *)greallocn(mapA, size, sizeof(Unicode)); memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode)); } if (n == 1) { mapA[u0] = uBuf[0]; } else { mapA[u0] = 0; if (sMapLenA == sMapSizeA) { sMapSizeA += 16; sMapA = (CharCodeToUnicodeString *) greallocn(sMapA, sMapSizeA, sizeof(CharCodeToUnicodeString)); } sMapA[sMapLenA].c = u0; for (i = 0; i < n; ++i) { sMapA[sMapLenA].u[i] = uBuf[i]; } sMapA[sMapLenA].len = n; ++sMapLenA; } if (u0 >= len) { len = u0 + 1; } } fclose(f); ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue, sMapA, sMapLenA, sMapSizeA); gfree(mapA); return ctu; } CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) { return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0); } CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) { CharCodeToUnicode *ctu; char *p; ctu = new CharCodeToUnicode(NULL); p = buf->getCString(); ctu->parseCMap1(&getCharFromString, &p, nBits); return ctu; } void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) { char *p; p = buf->getCString(); parseCMap1(&getCharFromString, &p, nBits); } void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data, int nBits) { PSTokenizer *pst; char tok1[256], tok2[256], tok3[256]; int n1, n2, n3; CharCode i; CharCode maxCode, code1, code2; GString *name; FILE *f; maxCode = (nBits == 8) ? 0xff : (nBits == 16) ? 0xffff : 0xffffffff; pst = new PSTokenizer(getCharFunc, data); pst->getToken(tok1, sizeof(tok1), &n1); while (pst->getToken(tok2, sizeof(tok2), &n2)) { if (!strcmp(tok2, "usecmap")) { if (tok1[0] == '/') { name = new GString(tok1 + 1); if ((f = globalParams->findToUnicodeFile(name))) { parseCMap1(&getCharFromFile, f, nBits); fclose(f); } else { error(errSyntaxError, -1, "Couldn't find ToUnicode CMap file for '{1:t}'", name); } delete name; } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "beginbfchar")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endbfchar")) { break; } if (!pst->getToken(tok2, sizeof(tok2), &n2) || !strcmp(tok2, "endbfchar")) { error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap"); break; } if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && tok2[0] == '<' && tok2[n2 - 1] == '>')) { error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } tok1[n1 - 1] = tok2[n2 - 1] = '\0'; if (!parseHex(tok1 + 1, n1 - 2, &code1)) { error(errSyntaxWarning, -1, "Illegal entry in bfchar block in ToUnicode CMap"); continue; } if (code1 > maxCode) { error(errSyntaxWarning, -1, "Invalid entry in bfchar block in ToUnicode CMap"); } addMapping(code1, tok2 + 1, n2 - 2, 0); } pst->getToken(tok1, sizeof(tok1), &n1); } else if (!strcmp(tok2, "beginbfrange")) { while (pst->getToken(tok1, sizeof(tok1), &n1)) { if (!strcmp(tok1, "endbfrange")) { break; } if (!pst->getToken(tok2, sizeof(tok2), &n2) || !strcmp(tok2, "endbfrange") || !pst->getToken(tok3, sizeof(tok3), &n3) || !strcmp(tok3, "endbfrange")) { error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap"); break; } if (!(tok1[0] == '<' && tok1[n1 - 1] == '>' && tok2[0] == '<' && tok2[n2 - 1] == '>')) { error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } tok1[n1 - 1] = tok2[n2 - 1] = '\0'; if (!parseHex(tok1 + 1, n1 - 2, &code1) || !parseHex(tok2 + 1, n2 - 2, &code2)) { error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap"); continue; } if (code1 > maxCode || code2 > maxCode) { error(errSyntaxWarning, -1, "Invalid entry in bfrange block in ToUnicode CMap"); if (code1 > maxCode) { code1 = maxCode; } if (code2 > maxCode) { code2 = maxCode; } } if (!strcmp(tok3, "[")) { i = 0; while (pst->getToken(tok1, sizeof(tok1), &n1) && code1 + i <= code2) { if (!strcmp(tok1, "]")) { break; } if (tok1[0] == '<' && tok1[n1 - 1] == '>') { tok1[n1 - 1] = '\0'; addMapping(code1 + i, tok1 + 1, n1 - 2, 0); } else { error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap"); } ++i; } } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') { tok3[n3 - 1] = '\0'; for (i = 0; code1 <= code2; ++code1, ++i) { addMapping(code1, tok3 + 1, n3 - 2, i); } } else { error(errSyntaxWarning, -1, "Illegal entry in bfrange block in ToUnicode CMap"); } } pst->getToken(tok1, sizeof(tok1), &n1); } else { strcpy(tok1, tok2); } } delete pst; } void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n, int offset) { CharCode oldLen, i; Unicode u; int j; if (code > 0xffffff) { // This is an arbitrary limit to avoid integer overflow issues. // (I've seen CMaps with mappings for .) return; } if (code >= mapLen) { oldLen = mapLen; mapLen = mapLen ? 2 * mapLen : 256; if (code >= mapLen) { mapLen = (code + 256) & ~255; } map = (Unicode *)greallocn(map, mapLen, sizeof(Unicode)); for (i = oldLen; i < mapLen; ++i) { map[i] = 0; } } if (n <= 4) { if (!parseHex(uStr, n, &u)) { error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap"); return; } map[code] = u + offset; } else { if (sMapLen >= sMapSize) { sMapSize = sMapSize + 16; sMap = (CharCodeToUnicodeString *) greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); } map[code] = 0; sMap[sMapLen].c = code; if ((sMap[sMapLen].len = n / 4) > maxUnicodeString) { sMap[sMapLen].len = maxUnicodeString; } for (j = 0; j < sMap[sMapLen].len; ++j) { if (!parseHex(uStr + j*4, 4, &sMap[sMapLen].u[j])) { error(errSyntaxWarning, -1, "Illegal entry in ToUnicode CMap"); return; } } sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset; ++sMapLen; } } CharCodeToUnicode::CharCodeToUnicode() { tag = NULL; map = NULL; mapLen = 0; sMap = NULL; sMapLen = sMapSize = 0; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } CharCodeToUnicode::CharCodeToUnicode(GString *tagA) { CharCode i; tag = tagA; mapLen = 256; map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); for (i = 0; i < mapLen; ++i) { map[i] = 0; } sMap = NULL; sMapLen = sMapSize = 0; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA, CharCode mapLenA, GBool copyMap, CharCodeToUnicodeString *sMapA, int sMapLenA, int sMapSizeA) { tag = tagA; mapLen = mapLenA; if (copyMap) { map = (Unicode *)gmallocn(mapLen, sizeof(Unicode)); memcpy(map, mapA, mapLen * sizeof(Unicode)); } else { map = mapA; } sMap = sMapA; sMapLen = sMapLenA; sMapSize = sMapSizeA; refCnt = 1; #if MULTITHREADED gInitMutex(&mutex); #endif } CharCodeToUnicode::~CharCodeToUnicode() { if (tag) { delete tag; } gfree(map); gfree(sMap); #if MULTITHREADED gDestroyMutex(&mutex); #endif } void CharCodeToUnicode::incRefCnt() { #if MULTITHREADED gLockMutex(&mutex); #endif ++refCnt; #if MULTITHREADED gUnlockMutex(&mutex); #endif } void CharCodeToUnicode::decRefCnt() { GBool done; #if MULTITHREADED gLockMutex(&mutex); #endif done = --refCnt == 0; #if MULTITHREADED gUnlockMutex(&mutex); #endif if (done) { delete this; } } GBool CharCodeToUnicode::match(GString *tagA) { return tag && !tag->cmp(tagA); } void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) { int i, j; if (!map) { return; } if (len == 1) { map[c] = u[0]; } else { for (i = 0; i < sMapLen; ++i) { if (sMap[i].c == c) { break; } } if (i == sMapLen) { if (sMapLen == sMapSize) { sMapSize += 8; sMap = (CharCodeToUnicodeString *) greallocn(sMap, sMapSize, sizeof(CharCodeToUnicodeString)); } ++sMapLen; } map[c] = 0; sMap[i].c = c; sMap[i].len = len; for (j = 0; j < len && j < maxUnicodeString; ++j) { sMap[i].u[j] = u[j]; } } } int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) { int i, j; if (!map) { u[0] = (Unicode)c; return 1; } if (c >= mapLen) { return 0; } if (map[c]) { u[0] = map[c]; return 1; } for (i = 0; i < sMapLen; ++i) { if (sMap[i].c == c) { for (j = 0; j < sMap[i].len && j < size; ++j) { u[j] = sMap[i].u[j]; } return j; } } return 0; } //------------------------------------------------------------------------ CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) { int i; size = sizeA; cache = (CharCodeToUnicode **)gmallocn(size, sizeof(CharCodeToUnicode *)); for (i = 0; i < size; ++i) { cache[i] = NULL; } } CharCodeToUnicodeCache::~CharCodeToUnicodeCache() { int i; for (i = 0; i < size; ++i) { if (cache[i]) { cache[i]->decRefCnt(); } } gfree(cache); } CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) { CharCodeToUnicode *ctu; int i, j; if (cache[0] && cache[0]->match(tag)) { cache[0]->incRefCnt(); return cache[0]; } for (i = 1; i < size; ++i) { if (cache[i] && cache[i]->match(tag)) { ctu = cache[i]; for (j = i; j >= 1; --j) { cache[j] = cache[j - 1]; } cache[0] = ctu; ctu->incRefCnt(); return ctu; } } return NULL; } void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) { int i; if (cache[size - 1]) { cache[size - 1]->decRefCnt(); } for (i = size - 1; i >= 1; --i) { cache[i] = cache[i - 1]; } cache[0] = ctu; ctu->incRefCnt(); } xpdf-3.03/xpdf/JArithmeticDecoder.h0000644000076400007640000000534311622305345016523 0ustar dereknderekn//======================================================================== // // JArithmeticDecoder.h // // Arithmetic decoder used by the JBIG2 and JPEG2000 decoders. // // Copyright 2002-2004 Glyph & Cog, LLC // //======================================================================== #ifndef JARITHMETICDECODER_H #define JARITHMETICDECODER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" class Stream; //------------------------------------------------------------------------ // JArithmeticDecoderStats //------------------------------------------------------------------------ class JArithmeticDecoderStats { public: JArithmeticDecoderStats(int contextSizeA); ~JArithmeticDecoderStats(); JArithmeticDecoderStats *copy(); void reset(); int getContextSize() { return contextSize; } void copyFrom(JArithmeticDecoderStats *stats); void setEntry(Guint cx, int i, int mps); private: Guchar *cxTab; // cxTab[cx] = (i[cx] << 1) + mps[cx] int contextSize; friend class JArithmeticDecoder; }; //------------------------------------------------------------------------ // JArithmeticDecoder //------------------------------------------------------------------------ class JArithmeticDecoder { public: JArithmeticDecoder(); ~JArithmeticDecoder(); void setStream(Stream *strA) { str = strA; dataLen = 0; limitStream = gFalse; } void setStream(Stream *strA, int dataLenA) { str = strA; dataLen = dataLenA; limitStream = gTrue; } // Start decoding on a new stream. This fills the byte buffers and // runs INITDEC. void start(); // Restart decoding on an interrupted stream. This refills the // buffers if needed, but does not run INITDEC. (This is used in // JPEG 2000 streams when codeblock data is split across multiple // packets/layers.) void restart(int dataLenA); // Read any leftover data in the stream. void cleanup(); // Decode one bit. int decodeBit(Guint context, JArithmeticDecoderStats *stats); // Decode eight bits. int decodeByte(Guint context, JArithmeticDecoderStats *stats); // Returns false for OOB, otherwise sets * and returns true. GBool decodeInt(int *x, JArithmeticDecoderStats *stats); Guint decodeIAID(Guint codeLen, JArithmeticDecoderStats *stats); void resetByteCounter() { nBytesRead = 0; } Guint getByteCounter() { return nBytesRead; } private: Guint readByte(); int decodeIntBit(JArithmeticDecoderStats *stats); void byteIn(); static Guint qeTab[47]; static int nmpsTab[47]; static int nlpsTab[47]; static int switchTab[47]; Guint buf0, buf1; Guint c, a; int ct; Guint prev; // for the integer decoder Stream *str; Guint nBytesRead; int dataLen; GBool limitStream; }; #endif xpdf-3.03/xpdf/findDis.xbm0000644000076400007640000000043111622305345014742 0ustar dereknderekn#define findDis_width 15 #define findDis_height 15 static unsigned char findDis_bits[] = { 0x10, 0x04, 0x28, 0x0a, 0x04, 0x10, 0xaa, 0x2a, 0x55, 0x55, 0x20, 0x02, 0x41, 0x41, 0x20, 0x02, 0x41, 0x41, 0xa0, 0x02, 0x01, 0x40, 0x20, 0x02, 0x01, 0x40, 0x20, 0x02, 0x15, 0x54}; xpdf-3.03/xpdf/OptionalContent.h0000644000076400007640000000642711622305345016156 0ustar dereknderekn//======================================================================== // // OptionalContent.h // // Copyright 2008 Glyph & Cog, LLC // //======================================================================== #ifndef OPTIONALCONTENT_H #define OPTIONALCONTENT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "Object.h" #include "CharTypes.h" class GString; class GList; class PDFDoc; class XRef; class OptionalContentGroup; class OCDisplayNode; //------------------------------------------------------------------------ class OptionalContent { public: OptionalContent(PDFDoc *doc); ~OptionalContent(); // Walk the list of optional content groups. int getNumOCGs(); OptionalContentGroup *getOCG(int idx); // Find an OCG by indirect reference. OptionalContentGroup *findOCG(Ref *ref); // Get the root node of the optional content group display tree // (which does not necessarily include all of the OCGs). OCDisplayNode *getDisplayRoot() { return display; } // Evaluate an optional content object -- either an OCG or an OCMD. // If is a valid OCG or OCMD, sets * and returns // true; otherwise returns false. GBool evalOCObject(Object *obj, GBool *visible); private: GBool evalOCVisibilityExpr(Object *expr, int recursion); XRef *xref; GList *ocgs; // all OCGs [OptionalContentGroup] OCDisplayNode *display; // root node of display tree }; //------------------------------------------------------------------------ // Values from the optional content usage dictionary. enum OCUsageState { ocUsageOn, ocUsageOff, ocUsageUnset }; //------------------------------------------------------------------------ class OptionalContentGroup { public: static OptionalContentGroup *parse(Ref *refA, Object *obj); ~OptionalContentGroup(); GBool matches(Ref *refA); Unicode *getName() { return name; } int getNameLength() { return nameLen; } OCUsageState getViewState() { return viewState; } OCUsageState getPrintState() { return printState; } GBool getState() { return state; } void setState(GBool stateA) { state = stateA; } private: OptionalContentGroup(Ref *refA, Unicode *nameA, int nameLenA, OCUsageState viewStateA, OCUsageState printStateA); Ref ref; Unicode *name; int nameLen; OCUsageState viewState, // suggested state when viewing printState; // suggested state when printing GBool state; // current state (on/off) }; //------------------------------------------------------------------------ class OCDisplayNode { public: static OCDisplayNode *parse(Object *obj, OptionalContent *oc, XRef *xref, int recursion = 0); OCDisplayNode(); ~OCDisplayNode(); Unicode *getName() { return name; } int getNameLength() { return nameLen; } OptionalContentGroup *getOCG() { return ocg; } int getNumChildren(); OCDisplayNode *getChild(int idx); private: OCDisplayNode(GString *nameA); OCDisplayNode(OptionalContentGroup *ocgA); void addChild(OCDisplayNode *child); void addChildren(GList *childrenA); GList *takeChildren(); Unicode *name; // display name (may be NULL) int nameLen; OptionalContentGroup *ocg; // NULL for display labels GList *children; // NULL if there are no children // [OCDisplayNode] }; #endif xpdf-3.03/xpdf/Error.cc0000644000076400007640000000310011622305345014246 0ustar dereknderekn//======================================================================== // // Error.cc // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "GString.h" #include "GlobalParams.h" #include "Error.h" static const char *errorCategoryNames[] = { "Syntax Warning", "Syntax Error", "Config Error", "Command Line Error", "I/O Error", "Permission Error", "Unimplemented Feature", "Internal Error" }; static void (*errorCbk)(void *data, ErrorCategory category, int pos, char *msg) = NULL; static void *errorCbkData = NULL; void setErrorCallback(void (*cbk)(void *data, ErrorCategory category, int pos, char *msg), void *data) { errorCbk = cbk; errorCbkData = data; } void CDECL error(ErrorCategory category, int pos, const char *msg, ...) { va_list args; GString *s; // NB: this can be called before the globalParams object is created if (!errorCbk && globalParams && globalParams->getErrQuiet()) { return; } va_start(args, msg); s = GString::formatv(msg, args); va_end(args); if (errorCbk) { (*errorCbk)(errorCbkData, category, pos, s->getCString()); } else { if (pos >= 0) { fprintf(stderr, "%s (%d): %s\n", errorCategoryNames[category], pos, s->getCString()); } else { fprintf(stderr, "%s: %s\n", errorCategoryNames[category], s->getCString()); } fflush(stderr); } delete s; } xpdf-3.03/xpdf/PDFCore.h0000644000076400007640000002547611622305345014265 0ustar dereknderekn//======================================================================== // // PDFCore.h // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #ifndef PDFCORE_H #define PDFCORE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "SplashTypes.h" #include "CharTypes.h" class GString; class GList; class SplashBitmap; class SplashPattern; class BaseStream; class PDFDoc; class Links; class LinkDest; class LinkAction; class TextPage; class HighlightFile; class CoreOutputDev; class PDFCore; //------------------------------------------------------------------------ // zoom factor //------------------------------------------------------------------------ #define zoomPage -1 #define zoomWidth -2 #define defZoom 125 //------------------------------------------------------------------------ //------------------------------------------------------------------------ // Number of pixels of matte color between pages in continuous mode. #define continuousModePageSpacing 3 //------------------------------------------------------------------------ // PDFCorePage //------------------------------------------------------------------------ class PDFCorePage { public: PDFCorePage(int pageA, int wA, int hA, int tileWA, int tileHA); ~PDFCorePage(); int page; GList *tiles; // cached tiles [PDFCoreTile] int xDest, yDest; // position of upper-left corner // in the drawing area int w, h; // size of whole page bitmap int tileW, tileH; // size of tiles Links *links; // hyperlinks for this page TextPage *text; // extracted text }; //------------------------------------------------------------------------ // PDFCoreTile //------------------------------------------------------------------------ class PDFCoreTile { public: PDFCoreTile(int xDestA, int yDestA); virtual ~PDFCoreTile(); int xMin, yMin, xMax, yMax; int xDest, yDest; Guint edges; SplashBitmap *bitmap; double ctm[6]; // coordinate transform matrix: // default user space -> device space double ictm[6]; // inverse CTM }; #define pdfCoreTileTopEdge 0x01 #define pdfCoreTileBottomEdge 0x02 #define pdfCoreTileLeftEdge 0x04 #define pdfCoreTileRightEdge 0x08 #define pdfCoreTileTopSpace 0x10 #define pdfCoreTileBottomSpace 0x20 //------------------------------------------------------------------------ // PDFHistory //------------------------------------------------------------------------ struct PDFHistory { GString *fileName; int page; }; #define pdfHistorySize 50 //------------------------------------------------------------------------ // PDFCore //------------------------------------------------------------------------ class PDFCore { public: PDFCore(SplashColorMode colorModeA, int bitmapRowPadA, GBool reverseVideoA, SplashColorPtr paperColorA, GBool incrementalUpdate); virtual ~PDFCore(); //----- loadFile / displayPage / displayDest // Load a new file. Returns pdfOk or error code. virtual int loadFile(GString *fileName, GString *ownerPassword = NULL, GString *userPassword = NULL); #ifdef WIN32 // Load a new file. Returns pdfOk or error code. virtual int loadFile(wchar_t *fileName, int fileNameLen, GString *ownerPassword = NULL, GString *userPassword = NULL); #endif // Load a new file, via a Stream instead of a file name. Returns // pdfOk or error code. virtual int loadFile(BaseStream *stream, GString *ownerPassword = NULL, GString *userPassword = NULL); // Load an already-created PDFDoc object. virtual void loadDoc(PDFDoc *docA); // Clear out the current document, if any. virtual void clear(); // Same as clear(), but returns the PDFDoc object instead of // deleting it. virtual PDFDoc *takeDoc(GBool redraw); // Display (or redisplay) the specified page. If is // set, the window is vertically scrolled to the top; otherwise, no // scrolling is done. If is set, this page change is // added to the history list. virtual void displayPage(int topPageA, double zoomA, int rotateA, GBool scrollToTop, GBool addToHist); // Display a link destination. virtual void displayDest(LinkDest *dest, double zoomA, int rotateA, GBool addToHist); // Update the display, given the specified parameters. virtual void update(int topPageA, int scrollXA, int scrollYA, double zoomA, int rotateA, GBool force, GBool addToHist, GBool adjustScrollX); //----- page/position changes virtual GBool gotoNextPage(int inc, GBool top); virtual GBool gotoPrevPage(int dec, GBool top, GBool bottom); virtual GBool gotoNamedDestination(GString *dest); virtual GBool goForward(); virtual GBool goBackward(); virtual void scrollLeft(int nCols = 16); virtual void scrollRight(int nCols = 16); virtual void scrollUp(int nLines = 16); virtual void scrollUpPrevPage(int nLines = 16); virtual void scrollDown(int nLines = 16); virtual void scrollDownNextPage(int nLines = 16); virtual void scrollPageUp(); virtual void scrollPageDown(); virtual void scrollTo(int x, int y); virtual void scrollToLeftEdge(); virtual void scrollToRightEdge(); virtual void scrollToTopEdge(); virtual void scrollToBottomEdge(); virtual void scrollToTopLeft(); virtual void scrollToBottomRight(); virtual void zoomToRect(int pg, double ulx, double uly, double lrx, double lry); virtual void zoomCentered(double zoomA); virtual void zoomToCurrentWidth(); virtual void setContinuousMode(GBool cm); //----- selection // Selection color. void setSelectionColor(SplashColor color); // Current selected region. void setSelection(int newSelectPage, int newSelectULX, int newSelectULY, int newSelectLRX, int newSelectLRY); void moveSelection(int pg, int x, int y); GBool getSelection(int *pg, double *ulx, double *uly, double *lrx, double *lry); // Text extraction. GString *extractText(int pg, double xMin, double yMin, double xMax, double yMax); //----- find virtual GBool find(char *s, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly); virtual GBool findU(Unicode *u, int len, GBool caseSensitive, GBool next, GBool backward, GBool wholeWord, GBool onePageOnly); //----- coordinate conversion // user space: per-pace, as defined by PDF file; unit = point // device space: (0,0) is upper-left corner of a page; unit = pixel // window space: (0,0) is upper-left corner of drawing area; unit = pixel GBool cvtWindowToUser(int xw, int yw, int *pg, double *xu, double *yu); GBool cvtWindowToDev(int xw, int yw, int *pg, int *xd, int *yd); void cvtUserToWindow(int pg, double xy, double yu, int *xw, int *yw); void cvtUserToDev(int pg, double xu, double yu, int *xd, int *yd); void cvtDevToWindow(int pg, int xd, int yd, int *xw, int *yw); void cvtDevToUser(int pg, int xd, int yd, double *xu, double *yu); //----- password dialog virtual GString *getPassword() { return NULL; } //----- misc access PDFDoc *getDoc() { return doc; } int getPageNum() { return topPage; } double getZoom() { return zoom; } double getZoomDPI() { return dpi; } int getRotate() { return rotate; } GBool getContinuousMode() { return continuousMode; } virtual void setReverseVideo(GBool reverseVideoA); GBool canGoBack() { return historyBLen > 1; } GBool canGoForward() { return historyFLen > 0; } int getScrollX() { return scrollX; } int getScrollY() { return scrollY; } int getDrawAreaWidth() { return drawAreaWidth; } int getDrawAreaHeight() { return drawAreaHeight; } virtual void setBusyCursor(GBool busy) = 0; LinkAction *findLink(int pg, double x, double y); protected: int loadFile2(PDFDoc *newDoc); void addPage(int pg, int rot); void needTile(PDFCorePage *page, int x, int y); void xorRectangle(int pg, int x0, int y0, int x1, int y1, SplashPattern *pattern, PDFCoreTile *oneTile = NULL); int loadHighlightFile(HighlightFile *hf, SplashColorPtr color, SplashColorPtr selectColor, GBool selectable); PDFCorePage *findPage(int pg); static void redrawCbk(void *data, int x0, int y0, int x1, int y1, GBool composited); void redrawWindow(int x, int y, int width, int height, GBool needUpdate); virtual PDFCoreTile *newTile(int xDestA, int yDestA); virtual void updateTileData(PDFCoreTile *tileA, int xSrc, int ySrc, int width, int height, GBool composited); virtual void redrawRect(PDFCoreTile *tileA, int xSrc, int ySrc, int xDest, int yDest, int width, int height, GBool composited) = 0; void clippedRedrawRect(PDFCoreTile *tile, int xSrc, int ySrc, int xDest, int yDest, int width, int height, int xClip, int yClip, int wClip, int hClip, GBool needUpdate, GBool composited = gTrue); virtual void updateScrollbars() = 0; virtual GBool checkForNewFile() { return gFalse; } PDFDoc *doc; // current PDF file GBool continuousMode; // false for single-page mode, true for // continuous mode int drawAreaWidth, // size of the PDF display area drawAreaHeight; double maxUnscaledPageW, // maximum unscaled page size maxUnscaledPageH; int maxPageW; // maximum page width (only used in // continuous mode) int totalDocH; // total document height (only used in // continuous mode) int *pageY; // top coordinates for each page (only used // in continuous mode) int topPage; // page at top of window int midPage; // page at middle of window int scrollX, scrollY; // offset from top left corner of topPage // to top left corner of window double zoom; // current zoom level, in percent of 72 dpi double dpi; // current zoom level, in DPI int rotate; // current page rotation int selectPage; // page number of current selection int selectULX, // coordinates of current selection, selectULY, // in device space -- (ULX==LRX || ULY==LRY) selectLRX, // means there is no selection selectLRY; GBool dragging; // set while selection is being dragged GBool lastDragLeft; // last dragged selection edge was left/right GBool lastDragTop; // last dragged selection edge was top/bottom SplashColor selectXorColor; // selection xor color PDFHistory // page history queue history[pdfHistorySize]; int historyCur; // currently displayed page int historyBLen; // number of valid entries backward from // current entry int historyFLen; // number of valid entries forward from // current entry GList *pages; // cached pages [PDFCorePage] PDFCoreTile *curTile; // tile currently being rasterized PDFCorePage *curPage; // page to which curTile belongs SplashColor paperColor; CoreOutputDev *out; friend class PDFCoreTile; }; #endif xpdf-3.03/xpdf/XPDFTree.cc0000644000076400007640000006576111622305345014563 0ustar dereknderekn//======================================================================== // // XPDFTree.cc // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #include #include #include "gmem.h" #include "XPDFTreeP.h" //------------------------------------------------------------------------ #define xpdfTreeIndent 16 //------------------------------------------------------------------------ struct _XPDFTreeEntry { Widget widget; XPDFTreeEntry *children; XPDFTreeEntry *next; }; //------------------------------------------------------------------------ static void classPartInitialize(WidgetClass widgetClass); static void initialize(Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs); static void destroy(Widget widget); static void destroySubtree(XPDFTreeEntry *e); static void resize(Widget widget); static void redisplay(Widget widget, XEvent *event, Region region); static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e, XEvent *event, Region region); static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y); static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y); static Boolean setValues(Widget oldWidget, Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs); static void setValuesAlmost(Widget oldWidget, Widget newWidget, XtWidgetGeometry *request, XtWidgetGeometry *reply); static XtGeometryResult queryGeometry(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply); static XtGeometryResult geometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply); static void changeManaged(Widget widget); static void initConstraint(Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs); static void destroyConstraint(Widget widget); static void deleteSubtree(Widget widget); static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs); static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead); static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead); static void createGC(Widget widget); static void destroyGC(Widget widget); static void layout(Widget widget, Widget instigator); static int layoutSubtree(XPDFTreeWidget w, Widget instigator, XPDFTreeEntry *e, Position x, Position y, Boolean visible); static void calcSize(Widget widget, Widget instigator, Dimension *totalWidth, Dimension *totalHeight); static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator, XPDFTreeEntry *e, Dimension *width, Dimension *height); static Boolean needRelayout(Widget oldWidget, Widget newWidget); static void click(Widget widget, XEvent *event, String *params, Cardinal *numParams); static Boolean findPosition(XPDFTreeWidget w, int x, int y, XPDFTreeEntry **e, Boolean *onExpandIcon); static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y, XPDFTreeEntry **e, Boolean *onExpandIcon); //------------------------------------------------------------------------ static XtResource resources[] = { { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginWidth), XmRImmediate, (XtPointer)0 }, { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension, sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginHeight), XmRImmediate, (XtPointer)0 }, { XPDFNselectionCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf(XPDFTreeRec, tree.selectCallback), XmRImmediate, (XtPointer)NULL } }; static XmSyntheticResource synResources[] = { { XmNmarginWidth, sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginWidth), #if XmVERSION > 1 XmeFromHorizontalPixels, XmeToHorizontalPixels #else _XmFromHorizontalPixels, _XmToHorizontalPixels #endif }, { XmNmarginHeight, sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginHeight), #if XmVERSION > 1 XmeFromVerticalPixels, XmeToVerticalPixels #else _XmFromVerticalPixels, _XmToVerticalPixels #endif } }; static XtResource constraints[] = { { XPDFNentryParent, XPDFCentryParent, XmRWidget, sizeof(Widget), XtOffsetOf(XPDFTreeConstraintRec, tree.entryParent), XmRImmediate, (XtPointer)NULL }, { XPDFNentryExpanded, XPDFCentryExpanded, XmRBoolean, sizeof(Boolean), XtOffsetOf(XPDFTreeConstraintRec, tree.entryExpanded), XmRImmediate, (XtPointer)False }, { XPDFNentryPosition, XPDFCentryPosition, XmRInt, sizeof(int), XtOffsetOf(XPDFTreeConstraintRec, tree.entryPosition), XmRImmediate, (XtPointer)0 } }; static char defaultTranslations[] = ": XPDFTreeClick()"; static XtActionsRec actions[] = { { "XPDFTreeClick", click } }; externaldef(xpdftreeclassrec) XPDFTreeClassRec xpdfTreeClassRec = { { // Core (WidgetClass)&xmManagerClassRec, // superclass "XPDFTree", // class_name sizeof(XPDFTreeRec), // widget_size NULL, // class_initialize &classPartInitialize, // class_part_initialize FALSE, // class_inited &initialize, // initialize NULL, // initialize_hook XtInheritRealize, // realize actions, // actions XtNumber(actions), // num_actions resources, // resources XtNumber(resources), // num_resources NULLQUARK, // xrm_class TRUE, // compress_motion XtExposeCompressMaximal, // compress_exposure TRUE, // compress_enterleave FALSE, // visible_interest &destroy, // destroy &resize, // resize &redisplay, // expose &setValues, // set_values NULL, // set_values_hook &setValuesAlmost, // set_values_almost NULL, // get_values_hook NULL, // accept_focus XtVersion, // version NULL, // callback_private defaultTranslations, // tm_table &queryGeometry, // query_geometry NULL, // display_accelerator NULL // extension }, { // Composite &geometryManager, // geometry_manager &changeManaged, // change_managed XtInheritInsertChild, // insert_child XtInheritDeleteChild, // delete_child NULL // extension }, { // Constraint constraints, // constraint_resources XtNumber(constraints), // constraint_num_resources sizeof(XPDFTreeConstraintRec), // constraint_size &initConstraint, // constraint_initialize &destroyConstraint, // constraint_destroy &constraintSetValues, // constraint_set_values NULL // extension }, { // XmManager XtInheritTranslations, // translations #if XmVERSION > 1 synResources, // syn_resources XtNumber(synResources), // num_syn_resources #else NULL, // syn_resources 0, // num_syn_resources #endif NULL, // syn_constraint_resources 0, // num_syn_constraint_res's XmInheritParentProcess, // parent_process NULL // extension }, { // XPDFTree &createGC, // createGC &destroyGC, // destroyGC &layout, // layout &calcSize, // calcSize &needRelayout, // needRelayout NULL // extension } }; externaldef(xpdftreewidgetclass) WidgetClass xpdfTreeWidgetClass = (WidgetClass)&xpdfTreeClassRec; //------------------------------------------------------------------------ static void classPartInitialize(WidgetClass widgetCls) { XPDFTreeWidgetClass wc = (XPDFTreeWidgetClass)widgetCls; XPDFTreeWidgetClass sc = (XPDFTreeWidgetClass)wc->coreClass.superclass; // method inheritance if (wc->treeClass.createGC == XPDFInheritCreateGC) { wc->treeClass.createGC = sc->treeClass.createGC; } if (wc->treeClass.destroyGC == XPDFInheritDestroyGC) { wc->treeClass.destroyGC = sc->treeClass.destroyGC; } if (wc->treeClass.layout == XPDFInheritLayout) { wc->treeClass.layout = sc->treeClass.layout; } if (wc->treeClass.calcSize == XPDFInheritCalcSize) { wc->treeClass.calcSize = sc->treeClass.calcSize; } if (wc->treeClass.needRelayout == XPDFInheritNeedRelayout) { wc->treeClass.needRelayout = sc->treeClass.needRelayout; } } static void initialize(Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs) { XPDFTreeWidget nw = (XPDFTreeWidget)newWidget; XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget); nw->tree.root = NULL; nw->tree.redrawY = -1; if (cls->treeClass.createGC) { (*cls->treeClass.createGC)(newWidget); } else { createGC(newWidget); } } static void destroy(Widget widget) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget); if (w->tree.root) { destroySubtree(w->tree.root); w->tree.root = NULL; } if (cls->treeClass.destroyGC) { (*cls->treeClass.destroyGC)(widget); } else { destroyGC(widget); } } static void destroySubtree(XPDFTreeEntry *e) { if (e->children) { destroySubtree(e->children); } if (e->next) { destroySubtree(e->next); } } static void resize(Widget widget) { XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget); if (cls->treeClass.layout) { (*cls->treeClass.layout)(widget, NULL); } else { layout(widget, NULL); } } static void redisplay(Widget widget, XEvent *event, Region region) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XPDFTreeEntry *e; if (w->tree.redrawY >= 0) { XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w), 0, w->tree.redrawY, w->core.width, w->core.height, False); w->tree.redrawY = -1; } for (e = w->tree.root; e; e = e->next) { redisplaySubtree(w, e, event, region); } } static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e, XEvent *event, Region region) { XPDFTreeConstraint c; Position x, y, y2; XPDFTreeEntry *child; (*XtClass(e->widget)->core_class.expose)(e->widget, event, region); c = XPDFTreeCPart(e->widget); x = e->widget->core.x; y = e->widget->core.y + e->widget->core.height / 2; if (e->children) { if (c->entryExpanded) { drawExpandedIcon(w, x - 8, y); y2 = y; // make gcc happy for (child = e->children; child; child = child->next) { y2 = child->widget->core.y + child->widget->core.height / 2; XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC, x - 8, y2, x + 6, y2); redisplaySubtree(w, child, event, region); } XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC, x - 8, y + 2, x - 8, y2); } else { drawCollapsedIcon(w, x - 8, y); } } } static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y) { XPoint pts[4]; pts[0].x = x - 4; pts[0].y = y - 2; pts[1].x = x + 4; pts[1].y = y - 2; pts[2].x = x; pts[2].y = y + 2; pts[3].x = x - 4; pts[3].y = y - 2; XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC, pts, 4, CoordModeOrigin); } static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y) { XPoint pts[4]; pts[0].x = x - 2; pts[0].y = y - 4; pts[1].x = x - 2; pts[1].y = y + 4; pts[2].x = x + 2; pts[2].y = y; pts[3].x = x - 2; pts[3].y = y - 4; XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC, pts, 4, CoordModeOrigin); } static Boolean setValues(Widget oldWidget, Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs) { XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget; XPDFTreeWidget nw = (XPDFTreeWidget)newWidget; XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(nw); Boolean relayout, redisp; // check to see if layout-affecting resources have changed if (cls->treeClass.needRelayout) { relayout = (*cls->treeClass.needRelayout)((Widget)ow, (Widget)nw); } else { relayout = needRelayout((Widget)ow, (Widget)nw); } redisp = False; if (relayout) { // calculate a new ideal size (reset the widget size first so // calcSize will compute a new one) if (nw->core.width == ow->core.width) { nw->core.width = 0; } if (nw->core.height == ow->core.height) { nw->core.height = 0; } if (cls->treeClass.calcSize) { (*cls->treeClass.calcSize)((Widget)nw, NULL, &nw->core.width, &nw->core.height); } else { calcSize((Widget)nw, NULL, &nw->core.width, &nw->core.height); } // if resources have changed but size hasn't, layout manually // (because Xt just looks at the size) if (nw->core.width == ow->core.width && nw->core.height == ow->core.height) { if (cls->treeClass.layout) { (*cls->treeClass.layout)((Widget)nw, NULL); } else { layout((Widget)nw, NULL); } redisp = True; } } return redisp; } static void setValuesAlmost(Widget oldWidget, Widget newWidget, XtWidgetGeometry *request, XtWidgetGeometry *reply) { XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget); // our parent rejected a geometry request, so accept the compromise // and relayout if (!reply->request_mode) { if (cls->treeClass.layout) { (*cls->treeClass.layout)(newWidget, NULL); } else { layout(newWidget, NULL); } } *request = *reply; } static XtGeometryResult queryGeometry(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) { XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget); if (!XtIsRealized(widget)) { reply->width = XtWidth(widget); reply->height = XtHeight(widget); } else { reply->width = 0; reply->height = 0; } if (cls->treeClass.calcSize) { (*cls->treeClass.calcSize)(widget, NULL, &reply->width, &reply->height); } else { calcSize(widget, NULL, &reply->width, &reply->height); } #if XmVERSION > 1 return XmeReplyToQueryGeometry(widget, request, reply); #else if ((request->request_mode & CWWidth) && (request->request_mode & CWHeight) && request->width == reply->width && request->height == reply->height) { return XtGeometryYes; } if (reply->width == XtWidth(widget) && reply->height == XtHeight(widget)) { return XtGeometryNo; } reply->request_mode = CWWidth | CWHeight; return XtGeometryAlmost; #endif } static XtGeometryResult geometryManager(Widget widget, XtWidgetGeometry *request, XtWidgetGeometry *reply) { XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget); XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(w); Dimension curWidth, curHeight, curBW; XtWidgetGeometry parentReq; XtGeometryResult result; // deny any requests for a new position if ((request->request_mode & CWX) || (request->request_mode & CWY)) { return XtGeometryNo; } // save the current geometry curWidth = w->core.width; curHeight = w->core.height; curBW = w->core.border_width; // make the requested changes if (request->request_mode & CWWidth) { w->core.width = request->width; } if (request->request_mode & CWHeight) { w->core.height = request->height; } if (request->request_mode & CWBorderWidth) { w->core.border_width = request->border_width; } // calculate the new ideal size parentReq.width = 0; parentReq.height = 0; if (cls->treeClass.calcSize) { (*cls->treeClass.calcSize)((Widget)w, widget, &parentReq.width, &reply->height); } else { calcSize((Widget)w, widget, &parentReq.width, &reply->height); } // send geometry request to our parent parentReq.request_mode = CWWidth | CWHeight; if (request->request_mode & XtCWQueryOnly) { parentReq.request_mode |= XtCWQueryOnly; } result = XtMakeGeometryRequest((Widget)w, &parentReq, NULL); if (result == XtGeometryAlmost) { result = XtGeometryNo; } if (result == XtGeometryNo || (request->request_mode & XtCWQueryOnly)) { // restore the original geometry w->core.width = curWidth; w->core.height = curHeight; w->core.border_width = curBW; } else { if (cls->treeClass.layout) { (*cls->treeClass.layout)((Widget)w, widget); } else { layout((Widget)w, widget); } } return result; } static void changeManaged(Widget widget) { Dimension width, height; XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget); // compute the ideal size if (!XtIsRealized(widget)) { width = XtWidth(widget); height = XtHeight(widget); } else { width = 0; height = 0; } if (cls->treeClass.calcSize) { (*cls->treeClass.calcSize)(widget, NULL, &width, &height); } else { calcSize(widget, NULL, &width, &height); } // make resize request to parent -- keep asking until we get a yes // or no while (XtMakeResizeRequest(widget, width, height, &width, &height) == XtGeometryAlmost) ; // relayout if (cls->treeClass.layout) { (*cls->treeClass.layout)(widget, NULL); } else { layout(widget, NULL); } #if XmVERSION > 1 // update keyboard traversal XmeNavigChangeManaged(widget); #else _XmNavigChangeManaged(widget); #endif } static void initConstraint(Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs) { XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget); XPDFTreeConstraint c; c = XPDFTreeCPart(newWidget); c->e = (XPDFTreeEntry *)gmalloc(sizeof(XPDFTreeEntry)); c->e->widget = newWidget; c->e->children = NULL; c->e->next = NULL; if (c->entryParent) { insertChildOnList(c->e, &XPDFTreeCPart(c->entryParent)->e->children); } else { insertChildOnList(c->e, &w->tree.root); } } static void destroyConstraint(Widget widget) { deleteSubtree(widget); } static void deleteSubtree(Widget widget) { XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget); XPDFTreeConstraint c; c = XPDFTreeCPart(widget); if (!c->e) { return; } while (c->e->children) { deleteSubtree(c->e->children->widget); } if (c->entryParent) { deleteChildFromList(c->e, &XPDFTreeCPart(c->entryParent)->e->children); } else { deleteChildFromList(c->e, &w->tree.root); } gfree(c->e); c->e = NULL; } static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget, Widget newWidget, ArgList args, Cardinal *numArgs) { XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget); XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass((Widget)w); XPDFTreeConstraint oc, nc; Boolean relayout; Dimension width, height; if (!XtIsManaged(newWidget)) { return False; } oc = XPDFTreeCPart(oldWidget); nc = XPDFTreeCPart(newWidget); relayout = False; if (nc->entryParent != oc->entryParent || nc->entryPosition != oc->entryPosition) { if (oc->entryParent) { deleteChildFromList(oc->e, &XPDFTreeCPart(oc->entryParent)->e->children); } else { deleteChildFromList(oc->e, &w->tree.root); } if (nc->entryParent) { insertChildOnList(nc->e, &XPDFTreeCPart(nc->entryParent)->e->children); } else { insertChildOnList(nc->e, &w->tree.root); } relayout = True; } else if (nc->entryExpanded != oc->entryExpanded) { relayout = True; } if (relayout) { // calculate a new ideal size (reset the widget size first so // calcSize will compute a new one) width = 0; height = 0; if (cls->treeClass.calcSize) { (*cls->treeClass.calcSize)((Widget)w, NULL, &width, &height); } else { calcSize((Widget)w, NULL, &width, &height); } // make resize request to parent -- keep asking until we get a yes // or no while (XtMakeResizeRequest((Widget)w, width, height, &width, &height) == XtGeometryAlmost) ; // relayout the widget if (cls->treeClass.layout) { (*cls->treeClass.layout)((Widget)w, NULL); } else { layout((Widget)w, NULL); } } return relayout; } static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) { int pos; XPDFTreeEntry *e2; pos = XPDFTreeCPart(e->widget)->entryPosition; if (!*listHead || pos < XPDFTreeCPart((*listHead)->widget)->entryPosition) { e->next = *listHead; *listHead = e; } else { for (e2 = *listHead; e2->next && pos >= XPDFTreeCPart(e2->next->widget)->entryPosition; e2 = e2->next) ; e->next = e2->next; e2->next = e; } } static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) { XPDFTreeEntry **p; for (p = listHead; *p; p = &(*p)->next) { if (*p == e) { *p = e->next; e->next = NULL; return; } } } static void createGC(Widget widget) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XGCValues gcValues; gcValues.foreground = w->manager.foreground; gcValues.line_width = 0; gcValues.line_style = LineSolid; w->tree.plainGC = XtGetGC(widget, GCForeground | GCLineWidth | GCLineStyle, &gcValues); gcValues.line_style = LineOnOffDash; gcValues.dashes = 1; gcValues.dash_offset = 0; w->tree.dottedGC = XtGetGC(widget, GCForeground | GCLineWidth | GCLineStyle | GCDashList | GCDashOffset, &gcValues); } static void destroyGC(Widget widget) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XtReleaseGC(widget, w->tree.plainGC); XtReleaseGC(widget, w->tree.dottedGC); } static void layout(Widget widget, Widget instigator) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XPDFTreeEntry *e; Position x, y; x = w->tree.marginWidth + xpdfTreeIndent; y = w->tree.marginHeight; for (e = w->tree.root; e; e = e->next) { y = layoutSubtree(w, instigator, e, x, y, True); } } static int layoutSubtree(XPDFTreeWidget w, Widget instigator, XPDFTreeEntry *e, Position x, Position y, Boolean visible) { Widget ew; XPDFTreeEntry *child; XPDFTreeConstraint c; int dy; ew = e->widget; if (!XtIsManaged(ew)) { return y; } c = XPDFTreeCPart(ew); // place this entry if (ew) { if (visible) { if (ew == instigator) { ew->core.x = x; ew->core.y = y; } else { #if XmVERSION > 1 XmeConfigureObject(ew, x, y, ew->core.width, ew->core.height, ew->core.border_width); #else _XmConfigureObject(ew, x, y, ew->core.width, ew->core.height, ew->core.border_width); #endif } dy = ew->core.height + 2 * ew->core.border_width; // this is a kludge to avoid crashes if the widget becomes too // tall if ((int)y + dy > 32767) { y = 32767; } else { y += dy; } } } // place this entry's children x += xpdfTreeIndent; for (child = e->children; child; child = child->next) { y = layoutSubtree(w, instigator, child, x, y, visible && (!c || c->entryExpanded)); } return y; } static void calcSize(Widget widget, Widget instigator, Dimension *totalWidth, Dimension *totalHeight) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XPDFTreeEntry *e; int h1; Dimension w1, w2, h2; w1 = h1 = 0; for (e = w->tree.root; e; e = e->next) { calcSubtreeSize(w, instigator, e, &w2, &h2); if (w2 > w1) { w1 = w2; } h1 += (int)h2; } w1 += xpdfTreeIndent + 2 * w->tree.marginWidth; h1 += 2 * (int)w->tree.marginHeight; if (h1 == 0) { h1 = 1; } else if (h1 > 32767) { // this is a kludge to avoid crashes if the widget becomes too // tall h1 = 32767; } if (!*totalWidth) { *totalWidth = w1; } if (!*totalHeight) { *totalHeight = (Dimension)h1; } } static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator, XPDFTreeEntry *e, Dimension *width, Dimension *height) { Widget ew; XPDFTreeEntry *child; XPDFTreeConstraint c; XtWidgetGeometry geom; int h1; Dimension w1, w2, h2; ew = e->widget; if (!XtIsManaged(ew)) { *width = *height = 0; return; } c = XPDFTreeCPart(ew); // get size of this entry if (ew) { if (!XtIsManaged(ew)) { *width = *height = 0; return; } if (ew == instigator) { w1 = ew->core.width; h1 = (int)ew->core.height; } else { XtQueryGeometry(ew, NULL, &geom); w1 = (geom.request_mode & CWWidth) ? geom.width : ew->core.width; h1 = (int)((geom.request_mode & CWHeight) ? geom.height : ew->core.height); } h1 += 2 * (int)ew->core.border_width; } else { // root of tree w1 = 0; h1 = 0; } // if this entry is expanded, get size of all of its children if (c->entryExpanded) { for (child = e->children; child; child = child->next) { calcSubtreeSize(w, instigator, child, &w2, &h2); w2 += xpdfTreeIndent; if (w2 > w1) { w1 = w2; } h1 += (int)h2; } } // this is a kludge to avoid crashes if the widget becomes too tall if (h1 > 32767) { h1 = 32767; } *width = w1; *height = h1; } static Boolean needRelayout(Widget oldWidget, Widget newWidget) { XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget; XPDFTreeWidget nw = (XPDFTreeWidget)newWidget; if (nw->tree.marginWidth != ow->tree.marginWidth || nw->tree.marginHeight != ow->tree.marginHeight) { return True; } return False; } static void click(Widget widget, XEvent *event, String *params, Cardinal *numParams) { XPDFTreeWidget w = (XPDFTreeWidget)widget; XButtonPressedEvent *bpe; XPDFTreeEntry *e; Boolean onExpandIcon; XPDFTreeConstraint c; XPDFTreeSelectCallbackStruct cbs; if (event->type != ButtonPress) { return; } bpe = (XButtonPressedEvent *)event; if (findPosition(w, bpe->x, bpe->y, &e, &onExpandIcon)) { if (onExpandIcon) { c = XPDFTreeCPart(e->widget); w->tree.redrawY = e->widget->core.y; XtVaSetValues(e->widget, XPDFNentryExpanded, !c->entryExpanded, NULL); } else { XmProcessTraversal(e->widget, XmTRAVERSE_CURRENT); XtCallActionProc(widget, "ManagerGadgetActivate", event, NULL, 0); cbs.reason = XmCR_ACTIVATE; cbs.event = event; cbs.selectedItem = e->widget; XtCallCallbackList(widget, w->tree.selectCallback, &cbs); } } } static Boolean findPosition(XPDFTreeWidget w, int x, int y, XPDFTreeEntry **e, Boolean *onExpandIcon) { XPDFTreeEntry *e2; for (e2 = w->tree.root; e2; e2 = e2->next) { *e = e2; if (findPositionInSubtree(w, x, y, e, onExpandIcon)) { return True; } } return False; } // If (x,y) falls on either an expand/collapse icon or a label gadget, // set * and * and return true. static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y, XPDFTreeEntry **e, Boolean *onExpandIcon) { Widget child; XPDFTreeConstraint c; XPDFTreeEntry *e2; int y1; child = (*e)->widget; y1 = child->core.y + child->core.height / 2; if (x >= child->core.x && x < child->core.x + child->core.width && y >= child->core.y && y < child->core.y + child->core.height) { *onExpandIcon = False; return True; } else if (x >= child->core.x - 16 && x < child->core.x - 4 && y >= y1 - 6 && y < y1 + 6 && (*e)->children) { *onExpandIcon = True; return True; } c = XPDFTreeCPart(child); if (!c || c->entryExpanded) { for (e2 = (*e)->children; e2; e2 = e2->next) { *e = e2; if (findPositionInSubtree(w, x, y, e, onExpandIcon)) { return True; } } } return False; } Widget XPDFCreateTree(Widget parent, char *name, ArgList argList, Cardinal numArgs) { return XtCreateWidget(name, xpdfTreeWidgetClass, parent, argList, numArgs); } xpdf-3.03/aconf.h.in0000644000076400007640000000330411622305345013557 0ustar dereknderekn/* * aconf.h * * Copyright 2002-2003 Glyph & Cog, LLC */ #ifndef ACONF_H #define ACONF_H #include /* * Use A4 paper size instead of Letter for PostScript output. */ #undef A4_PAPER /* * Do not allow text selection. */ #undef NO_TEXT_SELECT /* * Include support for OPI comments. */ #undef OPI_SUPPORT /* * Enable multithreading support. */ #undef MULTITHREADED /* * Enable C++ exceptions. */ #undef USE_EXCEPTIONS /* * Enable word list support. */ #undef TEXTOUT_WORD_LIST /* * Use fixed point (instead of floating point) arithmetic. */ #undef USE_FIXEDPOINT /* * Directory with the Xpdf app-defaults file. */ #undef APPDEFDIR /* * Full path for the system-wide xpdfrc file. */ #undef SYSTEM_XPDFRC /* * Various include files and functions. */ #undef HAVE_DIRENT_H #undef HAVE_SYS_NDIR_H #undef HAVE_SYS_DIR_H #undef HAVE_NDIR_H #undef HAVE_SYS_SELECT_H #undef HAVE_SYS_BSDTYPES_H #undef HAVE_STRINGS_H #undef HAVE_BSTRING_H #undef HAVE_POPEN #undef HAVE_MKSTEMP #undef HAVE_MKSTEMPS #undef SELECT_TAKES_INT #undef HAVE_STD_SORT #undef HAVE_FSEEKO #undef HAVE_FSEEK64 #undef _FILE_OFFSET_BITS #undef _LARGE_FILES #undef _LARGEFILE_SOURCE #undef HAVE_XTAPPSETEXITFLAG /* * This is defined if using libXpm. */ #undef HAVE_X11_XPM_H /* * This is defined if using t1lib. */ #undef HAVE_T1LIB_H /* * One of these is defined if using FreeType 2. */ #undef HAVE_FREETYPE_H #undef HAVE_FREETYPE_FREETYPE_H /* * This is defined if using libpaper. */ #undef HAVE_PAPER_H /* * Enable support for loading plugins. */ #undef ENABLE_PLUGINS /* * Defined if the Splash library is avaiable. */ #undef HAVE_SPLASH /* * Enable support for CMYK output. */ #undef SPLASH_CMYK #endif xpdf-3.03/ANNOUNCE0000644000076400007640000000341011622305344013041 0ustar derekndereknSubject: ANNOUNCE: Xpdf 3.03 - a PDF viewer for X Glyph & Cog, LLC is pleased to announce a new version of Xpdf, the open source Portable Document Format (PDF) viewer for X. The Xpdf project also includes a PDF text extractor, PDF-to-PostScript converter, and various other utilities. Xpdf runs under the X Window System on Unix, VMS, and OS/2. The non-X components (pdftops, pdftotext, etc.) also run on Win32 systems and should run on pretty much any system with a decent C++ compiler. Major changes: * Added the "fixed pitch" text extraction mode. * Modified "pdftops -paper match" to handle PDF files with different-sized pages, i.e., it will now select the matching paper size on a page-by-page basis. * Add ability for pdftoppm to write to stdout. * Added the pdfdetach tool. * Implemented 256-bit AES decryption. * Commented out the t1lib section in the configure script -- t1lib has some potential security holes, and hasn't been updated in years. * Redesigned the font configuration xpdfrc commands: removed the displayFontT1, displayFontTT, displayNamedCIDFontT1, displayCIDFontT1, displayNamedCIDFontTT, displayCIDFontTT, psFont, psNamedFont16, and psFont16 commands; added the fontFile, fontFileCC, psResidentFont, psResidentFont16, and psResidentFontCC commands. * Switched from GPLv2 to dual v2/v3 licensing. See the `CHANGES' file for a complete list of changes. Source (C++ and C) is available, and it should be fairly easy to compile for UNIX, VMS, OS/2, and Win32. More information, source code, and precompiled binaries are on the xpdf web page and ftp site: http://www.foolabs.com/xpdf/ ftp://ftp.foolabs.com/pub/xpdf/ For information on commercial licensing and consulting, please see the Glyph & Cog web site: http://www.glyphandcog.com/ xpdf-3.03/vms_make.com0000644000076400007640000004675011622305345014231 0ustar dereknderekn$!======================================================================== $! $! Main Xpdf compile script for VMS. $! $! Written by Patrick Moreau, Martin P.J. Zinser. $! $! Copyright 1996-2003 Glyph & Cog, LLC $! $!======================================================================== $! $! This procedure takes up to three (optional) parameters: $! $! 1.) Configuration settings: $! $! a4 - Use european A4 as the default paper size. $! $! no_text_select - Disable text selection in Xpdf $! $! opi_support - Compile Xpdf with support for the Open Prepress $! Interface (OPI) $! $! 2.) Compiler detection: $! $! In case you want to override the automatic compiler detection $! specify either DECC or GCC as the second paramter, $! e.g. @vms_make "" GCC $! $! 3.) System Xpdf resource file $! $! The default for this is decw$system_defaults:xpdfrc.dat, since this $! is the standard place for systemwide Xdefaults files on OpenVMS. You $! may provide a different file in p3. $! $! External libraries (like T1lib, Freetype, and XPM) are supported via the $! config file VMSLIB.DAT. Please check the sample file, which will be created $! by this procedure upon first invocation, for the information you need to $! provide $! $! Sample invocation of the script: $! @vms_make a4,opi_support "" $! $! In case of problems with the compile you may contact me at $! zinser@decus.de (preferred) or zinser@sysdev.deutsche-boerse.com (work). $! $!======================================================================== $! $ on error then goto err_exit $! $! $! Just some general constants... $! $ true = 1 $ false = 0 $ xpdf_link :== link $ tmpnam = "temp_" + f$getjpi("","pid") $ tc = tmpnam + ".c" $! $! Setup variables holding "config" information $! $ aconf_in_file = "aconf_h.in#aconf.h_in#aconf.h.in" $ name = "Xpdf" $ version = "?.?" $ mydefs = "#" $ xlibs = "xt#xmu#motif" $ cxxdefs = "" $ libdefs = "\" $ libincs = "" $ float = "" $ compress_def = false $ ft2def = false $ x11_save = "" $ p2 = f$edit(p2,"upcase,trim") $ if f$edit(p3,"trim") .eqs. "" $ then $ resfil = "decw$system_defaults:xpdfrc.dat" $ else $ resfil = "'p3'" $ endif $! $ gosub proc_config $ gosub check_version $! $! Start building the option file $! $ open/write optf xpdf.opt $ open/write topt tmp.opt $ write optf "Identification=""''name' ''version'""" $ gosub check_create_vmslib $ gosub check_xlib $! $ if (f$getsyi("HW_MODEL").ge.1024) .and. - (f$locate("T1LIB",f$edit(libdefs,"UPCASE")) .lt. f$length(libdefs)) - then float = "/float=ieee_float" $ incs = "sys$library:,[-],[],[-.goo]''libincs'" $! $ gosub check_compiler $ close optf $ close topt $! $! aconf.h.in might be mapped in different ways, so go figure $! $ i = 0 $FIND_ACONF: $ fname = f$element(i,"#",aconf_in_file) $ if fname .eqs. "#" then goto AMISS_ERR $ if f$search(fname) .eqs. "" $ then $ i = i + 1 $ goto find_aconf $ endif $ open/read/err=aconf_err aconf_in 'fname' $ open/write aconf aconf.h $ACONF_LOOP: $ read/end_of_file=aconf_exit aconf_in line $ work = f$edit(line, "compress,trim") $ if f$extract(0,6,work) .nes. "#undef" $ then $ write aconf line $ else $ def = f$element(1," ",work) $ if ((f$locate("\''def'\",f$edit(libdefs,"UPCASE")) .lt. f$length(libdefs)) - .or. (f$locate("#''def'#",f$edit(mydefs,"UPCASE")) .lt. f$length(mydefs))) $ then $ write aconf "#define ", def, " 1" $ else $ gosub check_config $ endif $ endif $! $! Make sure old-style VMS is defined along with __VMS $! $ if f$locate("define ACONF_H",line) .lt. f$length(line) $ then $ write aconf "#define VMS 1" $ endif $ goto aconf_loop $ACONF_EXIT: $ close aconf_in $ close aconf $ write sys$output "Compiling in [.GOO]" $ set default [.goo] $ @vms_make $ write sys$output "Compiling in [.XPDF]" $ set default [-.xpdf] $ @vms_make $ set default [-] $ gosub reset_env $ dele/noconf/nolog tmp.opt;* $ exit $ACONF_ERR: $ write sys$output "Input file ''fname' could not be opened" $ goto err_exit $AMISS_ERR: $ write sys$output "No source for aconf.h found." $ write sys$output "Tried any of ''aconf_in_file'" $CXX_ERR: $ write sys$output "C++ compiler required to build Xpdf" $ goto err_exit $FT2_ERR: $ write sys$output "Can not find [.internal] sub-dir in Freetype 2 tree" $ goto err_exit $ERR_EXIT: $ set message/facil/ident/sever/text $ gosub reset_env $ close/nolog aconf_in $ close/nolog aconf $ close/nolog optf $ close/nolog tmpc $ close/nolop topt $ write sys$output "Exiting..." $ exit 2 $!------------------------------------------------------------------------------ $! $! Take care of driver file with information about external libraries $! $CHECK_CREATE_VMSLIB: $! $ if f$search("VMSLIB.DAT") .eqs. "" $ then $ type/out=vmslib.dat sys$input ! ! This is a simple driver file with information used by vms_make.com to ! check if external libraries (like t1lib and freetype) are available on ! the system. ! ! Layout of the file: ! ! - Lines starting with ! are treated as comments ! - Elements in a data line are separated by # signs ! - The elements need to be listed in the following order ! 1.) Name of the Library (only used for informative messages ! from vms_make.com) ! 2.) Location where the object library can be found ! 3.) Location where the include files for the library can be found ! 4.) Include file used to verify library location ! 5.) CPP define to pass to the build to indicate availability of ! the library ! ! Example: The following lines show how definitions ! might look like. They are site specific and the locations of the ! library and include files need almost certainly to be changed. ! ! Location: All of the libaries can be found at the following addresses ! ! T1LIB: http://www.decus.de:8080/www/vms/sw/t1lib.htmlx ! FREETYPE: http://www.decus.de:8080/www/vms/sw/freetype2.htmlx ! XPM: http://www.decus.de:8080/www/vms/sw/xpm.htmlx ! LIBPAPER: http://www.decus.de:8080/www/vms/sw/libpaper.htmlx ! !T1LIB # pubbin:t1shr.exe # public$root:[xtools.libs.t1lib.lib.t1lib] # t1lib.h # HAVE_T1LIB_H !FREETYPE # pubbin:freetype2shr.exe # public$root:[xtools.libs.ft2.include.freetype],public$root:[xtools.libs.ft2.include] # freetype.h # HAVE_FREETYPE_H\FREETYPE2 !XPM # pubbin:libxpm.olb # X11: # xpm.h # HAVE_X11_XPM_H !LIBPAPER # pubbin:libpapershr.exe # public$root:[util.libs.paper.lib] # paper.h # HAVE_PAPER_H $ write sys$output "New driver file vmslib.dat created." $ write sys$output "Please customize libary locations for your site" $ write sys$output "and afterwards re-execute vms_make.com" $ write sys$output "Exiting..." $ close/nolog optf $ exit $ endif $! $! Open data file with location of libraries $! $ open/read/end=end_lib/err=err_lib libdata VMSLIB.DAT $LIB_LOOP: $ read/end=end_lib libdata libline $ libline = f$edit(libline, "UNCOMMENT,COLLAPSE") $ if libline .eqs. "" then goto LIB_LOOP ! Comment line $ libname = f$edit(f$element(0,"#",libline),"UPCASE") $ write sys$output "Processing ''libname' setup ..." $ libloc = f$element(1,"#",libline) $ libsrc = f$element(2,"#",libline) $ testinc = f$element(3,"#",libline) $ cppdef = f$element(4,"#",libline) $ old_cpp = f$locate("=1",cppdef) $ if old_cpp.lt.f$length(cppdef) then cppdef = f$extract(0,old_cpp,cppdef) $ if f$search("''libloc'").eqs. "" $ then $ write sys$output "Can not find library ''libloc' - Skipping ''libname'" $ goto LIB_LOOP $ endif $ libsrc_elem = 0 $ libsrc_found = false $LIBSRC_LOOP: $ libsrcdir = f$element(libsrc_elem,",",libsrc) $ if (libsrcdir .eqs. ",") then goto END_LIBSRC $ if f$search("''libsrcdir'''testinc'") .nes. "" then libsrc_found = true $ libsrc_elem = libsrc_elem + 1 $ goto LIBSRC_LOOP $END_LIBSRC: $ if .not. libsrc_found $ then $ write sys$output "Can not find includes at ''libsrc' - Skipping ''libname'" $ goto LIB_LOOP $ endif $ libdefs = libdefs + cppdef + "\" $ libincs = libincs + "," + libsrc $ lqual = "/lib" $ libtype = f$edit(f$parse(libloc,,,"TYPE"),"UPCASE") $ if f$locate("EXE",libtype) .lt. f$length(libtype) then lqual = "/share" $ write optf libloc , lqual $ write topt libloc , lqual $! $! Nasty hack to get the freetype includes to work $! $ if ((libname .eqs. "FREETYPE") .and. - (f$locate("FREETYPE2",cppdef) .lt. f$length(cppdef))) $ then $ if ((f$search("freetype:freetype.h") .nes. "") .and. - (f$search("freetype:[internal]ftobjs.h") .nes. "")) $ then $ write sys$output "Will use local definition of freetype logical" $ ft2def = false $ else $ ft2elem = 0 $FT2_LOOP: $ ft2srcdir = f$element(ft2elem,",",libsrc) $ if f$search("''ft2srcdir'''testinc'") .nes. "" $ then $ if f$search("''ft2srcdir'internal.dir") .nes. "" $ then $ ft2dev = f$parse("''ft2srcdir'",,,"device","no_conceal") $ ft2dir = f$parse("''ft2srcdir'",,,"directory","no_conceal") $ ft2conc = f$locate("][",ft2dir) $ ft2len = f$length(ft2dir) $ if ft2conc .lt. ft2len $ then $ ft2dir = f$extract(0,ft2conc,ft2dir) + - f$extract(ft2conc+2,ft2len-2,ft2dir) $ endif $ ft2dir = ft2dir - "]" + ".]" $ define freetype 'ft2dev''ft2dir','ft2srcdir' $ ft2def = true $ else $ goto ft2_err $ endif $ else $ ft2elem = ft2elem + 1 $ goto ft2_loop $ endif $ endif $ endif $! $! Yet another special treatment for Xpm/X11 $! $ if (libname .eqs. "XPM") $ then $ my_x11 = f$parse("''libsrc'xpm.h",,,"device") + - f$parse("''libsrc'xpm.h",,,"directory") $ x11_save = f$trnlnm("X11") $ define x11 'my_x11',decw$include $ endif $ goto LIB_LOOP $END_LIB: $ close libdata $ return $!------------------------------------------------------------------------------ $! $! Take care of driver file with information about external libraries $! $CHECK_CONFIG: $! $ if (def .eqs. "SYSTEM_XPDFRC") $ then $ write aconf "#define SYSTEM_XPDFRC """, resfil, """" $ else $ gosub check_cc_def $ endif $ return $!------------------------------------------------------------------------------ $! $! Check if this is a define relating to the properties of the C/C++ $! compiler $! $CHECK_CC_DEF: $ if (def .eqs. "HAVE_DIRENT_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_SYS_NDIR_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_SYS_DIR_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_NDIR_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_SYS_SELECT_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_SYS_BSDTYPES_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_STRINGS_H") $ then $ copy sys$input: 'tc $ deck #include int main(){ } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_POPEN") $ then $ copy sys$input: 'tc $ deck #include int main(){ FILE *pipe; pipe = popen("DIR","r"); pclose(pipe); } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_MKSTEMP") $ then $ copy sys$input: 'tc $ deck #include int main(){ mkstemp("tempXXXXXX"); } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_FSEEKO") $ then $ copy sys$input: 'tc $ deck #define _LARGEFILE #include int main(){ FILE *fp; fp = fopen("temp.txt","r"); fseeko(fp,1,SEEK_SET); fclose(fp); } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "_LARGE_FILES") $ then $ copy sys$input: 'tc $ deck #define _LARGEFILE #include int main(){ FILE *fp; fp = fopen("temp.txt","r"); fseeko(fp,1,SEEK_SET); fclose(fp); } $ eod $ gosub cc_prop_check $ return $ endif $ if (def .eqs. "HAVE_XTAPPSETEXITFLAG") $ then $ copy sys$input: 'tc $ deck #include int main(){ XtAppContext app_context; app_context = XtCreateApplicationContext(); XtAppSetExitFlag(app_context); return 0; } $ eod $ gosub cc_prop_check $ return $ endif $ write aconf "/* ", line, " */" $ return $!------------------------------------------------------------------------------ $! $! Process config settings passed from the command line $! (analog to Unix --enable-xxx) $! $PROC_CONFIG: $ if (p1.nes."") $ then $ i = 0 $ qual_list = f$edit(p1,"upcase") $DEF_LOOP: $ qual = f$element(i,",",qual_list) $ if qual .eqs. "," then goto FINISH_DEF $ i = i + 1 $ if (qual .eqs. "A4") $ then $ mydefs = mydefs + "A4_PAPER#" $ goto def_loop $ endif $ if (qual .eqs. "NO_TEXT_SELECT") $ then $ mydefs = mydefs + "NO_TEXT_SELECT#" $ goto def_loop $ endif $ if (qual .eqs. "OPI_SUPPORT") $ then $ mydefs = mydefs + "OPI_SUPPORT#" $ goto def_loop $ endif $ if (qual .eqs. "COMPRESS") $ then $ compress_def = true $ goto def_loop $ endif $ write sys$output "Qualifier ''qual' not recognized, will be ignored" $ goto def_loop $ endif $FINISH_DEF: $ return $! $!------------------------------------------------------------------------------ $! $! Look for the compiler used $! $CHECK_COMPILER: $ its_decc = (f$search("SYS$SYSTEM:CXX$COMPILER.EXE") .nes. "") $ its_gnuc = .not. its_decc .and. (f$trnlnm("gnu_cc") .nes. "") $! $! Exit if no compiler available $! $ if (.not. (its_decc .or. its_gnuc)) then goto CXX_ERR $! $! Override if requested from the commandline $! $ if (p2 .eqs. "DECC") $ then $ its_decc = true $ its_gnuc = false $ endif $ if (p1 .eqs. "GNUC") $ then $ its_decc = false $ its_gnuc = true $ endif $! $ if its_decc $ then $ ccomp :== "cc/decc/prefix=all ''float'" $! $! Take care of includes $! $ cc_user = f$trnlnm("DECC$USER_INCLUDE") $ cc_system = f$trnlnm("DECC$SYSTEM_INCLUDE") $ cxx_user = f$trnlnm("CXX$USER_INCLUDE") $ cxx_system = f$trnlnm("CXX$SYSTEM_INCLUDE") $ define decc$system_include 'incs' $ define decc$user_include 'incs' $ define cxx$user_include 'incs' $ define cxx$system_include 'incs' $! $! Check version of the C++ compiler $! $ create vms_xpdf_cc_test.cc $ cxx/lis=vms_xpdf_cc_test.lis/show=all vms_xpdf_cc_test.cc $ open list vms_xpdf_cc_test.lis $CXX_LIST: $ read/end=close_cxx list line $ start = f$locate("__DECCXX_VER",line) $ if start .ne. f$length(line) $ then $ cxx_ver = f$extract(start+13,8,line) $ if cxx_ver .gt. 60000000 $ then $ cxxdefs = "/warn=(disable=nosimpint)" $ xpdf_link :== cxxlink $ endif $ goto close_cxx $ endif $ goto cxx_list $CLOSE_CXX: $ close list $ delete/noconfirm vms_xpdf_cc_test.*;* $ cxxcomp :== "cxx/prefix=all ''cxxdefs' ''float' /include=cxx$user_include" $ endif $! $ if its_gnuc $ then $ ccomp :== "gcc/nocase/include=(''incs')" $ cxxcomp :== "gcc/plusplus/nocase/include=(''incs')" $ write optf "gnu_cc:[000000]gcclib.olb/lib" $ write optf "sys$share:vaxcrtl.exe/share" $ endif $ return $------------------------------------------------------------------------------- $RESET_ENV: $ delete/sym/glob cxxcomp $ delete/sym/glob ccomp $ delete/sym/glob xpdf_link $ if (ft2def) then deassign freetype $ if its_decc $ then $ if cc_user .eqs. "" $ then $ deass decc$user_include $ else $ define decc$user_include 'cc_user' $ endif $ if cc_system .eqs. "" $ then $ deass decc$system_include $ else $ define decc$system_include 'cc_system' $ endif $ if cxx_user .eqs. "" $ then $ deass cxx$user_include $ else $ define cxx$user_include 'cxx_user' $ endif $ if cxx_system .eqs. "" $ then $ deass cxx$system_include $ else $ define cxx$system_include 'cxx_system' $ endif $ endif $ if (x11_save .nes. "") then define x11 'x11_save' $ return $! $!------------------------------------------------------------------------------ $! $! Check for properties of C/C++ compiler $! $CC_PROP_CHECK: $ cc_prop = true $ set message/nofac/noident/nosever/notext $ on error then continue $ cc 'tmpnam' $ if .not. ($status) then cc_prop = false $ on error then continue $! The headers might lie about the capabilities of the RTL $ link/opt=tmp.opt 'tmpnam' $ if .not. ($status) then cc_prop = false $ set message/fac/ident/sever/text $ on error then goto err_exit $ delete/nolog 'tmpnam'.*;* $ if cc_prop $ then $ write sys$output "Checking for ''def'... yes" $ write aconf "#define ''def' 1" $ if (def .eqs. "HAVE_FSEEKO") .or. (def .eqs. "_LARGE_FILES") then - write aconf "#define _LARGEFILE" $ else $ write sys$output "Checking for ''def'... no" $ write aconf line $ endif $ return $!------------------------------------------------------------------------------ $! $! Check Xlibs and write to options file $! $CHECK_XLIB: $ If F$Type (xlibs) .nes. "STRING" Then xlibs = "" $ need_xt = f$locate("XT",f$edit(xlibs,"upcase")) .lt. f$length(xlibs) $ need_xmu = f$locate("XMU",f$edit(xlibs,"upcase")) .lt. f$length(xlibs) $ need_xm = f$locate("MOTIF",f$edit(xlibs,"upcase")) .lt. f$length(xlibs) $ On Error Then GoTo XUI $ @sys$update:decw$get_image_version sys$share:decw$xlibshr.exe decw$version $ if f$extract(4,3,decw$version).eqs."1.0" $ then $ if need_xt .or. need_xmu .or. need_xm $ then $ write optf "Sys$share:DECW$DWTLIBSHR.EXE/Share" $ write topt "Sys$share:DECW$DWTLIBSHR.EXE/Share" $ endif $ endif $ if f$extract(4,3,decw$version).eqs."1.1" $ then $ if need_xm then write optf "sys$share:decw$xmlibshr.exe/share" $ if need_xt then write optf "sys$share:decw$xtshr.exe/share" $ if nedd_xmu then write optf "sys$share:decw$xmulibshr.exe/share" $ if need_xm then write topt "sys$share:decw$xmlibshr.exe/share" $ if need_xt then write topt "sys$share:decw$xtshr.exe/share" $ if nedd_xmu then write topt "sys$share:decw$xmulibshr.exe/share" $ endif $ if f$extract(4,3,decw$version).eqs."1.2" $ then $ if need_xm then write optf "sys$share:decw$xmlibshr12.exe/share" $ if need_xt then write optf "sys$share:decw$xtlibshrr5.exe/share" $ if need_xmu then write optf "sys$share:decw$xmulibshrr5.exe/share" $ if need_xm then write topt "sys$share:decw$xmlibshr12.exe/share" $ if need_xt then write topt "sys$share:decw$xtlibshrr5.exe/share" $ if need_xmu then write topt "sys$share:decw$xmulibshrr5.exe/share" $ endif $ GoTo MAIN $ XUI: $! $ if need_xt .or. need_xmu $ then $ write optf "Sys$share:DECW$DWTLIBSHR.EXE/Share" $ write topt "Sys$share:DECW$DWTLIBSHR.EXE/Share" $ endif $ MAIN: $ on error then goto err_exit $ write optf "sys$share:decw$xlibshr.exe/share" $ write topt "sys$share:decw$xlibshr.exe/share" $ return $!------------------------------------------------------------------------------ $! $! Check version of Xpdf to build $! $CHECK_VERSION: $ open/read in [.xpdf]config.h $ check_string = "xpdfVersionNum" $vloop: $ read/end=vdone in rec $ if (f$element(1," " ,rec) .nes. check_string) then goto vloop $ start = f$locate(check_string,rec) + f$length(check_string) $ len = f$length(rec) - start $ version = f$edit(f$extract(start,len,rec),"COLLAPSE") $vdone: $ close in $ return $!------------------------------------------------------------------------------ xpdf-3.03/aconf2.h0000644000076400007640000000154711622305345013243 0ustar dereknderekn/* * aconf2.h * * This gets included by aconf.h, and contains miscellaneous global * settings not directly controlled by autoconf. This is a separate * file because otherwise the configure script will munge any * #define/#undef constructs. * * Copyright 2002-2003 Glyph & Cog, LLC */ #ifndef ACONF2_H #define ACONF2_H /* * This controls the use of the interface/implementation pragmas. */ #ifdef __GNUC__ #define USE_GCC_PRAGMAS #endif /* There is a bug in the version of gcc which ships with MacOS X 10.2 */ #if defined(__APPLE__) && defined(__MACH__) # include #endif #ifdef MAC_OS_X_VERSION_MAX_ALLOWED # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_2 # undef USE_GCC_PRAGMAS # endif #endif /* * Make sure WIN32 is defined if appropriate. */ #if defined(_WIN32) && !defined(WIN32) # define WIN32 #endif #endif xpdf-3.03/aconf-dj.h0000644000076400007640000000225611622305345013552 0ustar dereknderekn/* * aconf-dj.h * * Copyright 2002-2003 Glyph & Cog, LLC */ #ifndef ACONF_H #define ACONF_H /* * Use A4 paper size instead of Letter for PostScript output. */ #undef A4_PAPER /* * Do not allow text selection. */ #undef NO_TEXT_SELECT /* * Include support for OPI comments. */ #undef OPI_SUPPORT /* * Directory with the Xpdf app-defaults file. */ #undef APPDEFDIR /* * Full path for the system-wide xpdfrc file. */ #undef SYSTEM_XPDFRC /* * Various include files and functions. */ #define HAVE_DIRENT_H 1 #undef HAVE_SYS_NDIR_H #undef HAVE_SYS_DIR_H #undef HAVE_NDIR_H #undef HAVE_SYS_SELECT_H #undef HAVE_SYS_BSDTYPES_H #undef HAVE_STRINGS_H #undef HAVE_BSTRING_H #define HAVE_POPEN 1 #undef HAVE_MKSTEMP #undef SELECT_TAKES_INT #define HAVE_STD_SORT 1 #undef HAVE_FSEEK64 /* * This is defined if using libXpm. */ #undef HAVE_X11_XPM_H /* * This is defined if using t1lib. */ #undef HAVE_T1LIB_H /* * One of these is defined if using FreeType (version 1 or 2). */ #undef HAVE_FREETYPE_H #undef HAVE_FREETYPE_FREETYPE_H /* * This is defined if using FreeType version 2. */ #undef FREETYPE2 /* * This is defined if using libpaper. */ #undef HAVE_PAPER_H #endif xpdf-3.03/INSTALL0000644000076400007640000001454711622305344012756 0ustar derekndereknXpdf ==== version 3.03 2011-aug-15 The Xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. Email: derekn@foolabs.com WWW: http://www.foolabs.com/xpdf/ Compiling xpdf -------------- Xpdf is written in C++ (with a little bit of C). It should work with any ANSI-compliant C++ and C compilers. The systems and compilers it's been tested with are listed on the xpdf web page. Xpdf requires the Motif (or Lesstif) toolkit. The following notes give specific instructions for compiling on different systems. ************** *** UNIX *** ************** * Install FreeType 2 (this is required). WARNING: You must have version 2.0.5 or newer. Some older versions of XFree86 ship with an older version of FreeType, which means you'll need to explicitly set include and library paths to get the correct version: --with-freetype2-library=PATH --with-freetype2-includes=PATH (The include path is the directory which contains the freetype2 directory, i.e., do NOT include "freetype2" in the --with-freetype2-includes path. For example, with the default installation, the library path is /usr/local/lib and the include path is /usr/local/include/freetype2.) * If you have Motif (or Lesstif) installed in a non-standard place, you can use the following options to tell configure where to find it: --with-Xm-library=PATH --with-Xm-includes=PATH * Run the configure script: ./configure This should produce a set of makefiles customized for your system. The configure script accepts the following options (in addition to the usual things accepted by autoconf configure scripts): --prefix=PREFIX Changes the directory where xpdf is installed. The default is /usr/local. --enable-a4-paper Switches the default paper size for PostScript output (xpdf and pdftops) to A4. The default is Letter size. --enable-no-text-select With this option, xpdf will not copy text. (This is only useful on closed systems where the user can't get at the PDF file directly.) --enable-opi Enables support for generation of OPI (Open Prepress Interface) comments with pdftops. --sysconfdir=DIR Look for the system-wide xpdfrc config file in this directory. The default is PREFIX/etc. --with-appdef-dir=DIR Use the specified app-defaults directory. The default is /usr/lib/X11/app-defaults. If you need to pass specific options to the C and/or C++ compiler, you can set the CFLAGS and/or CXXFLAGS environment variables before running the configure script. Any options given that way will be added to the CFLAGS/CXXFLAGS used by all of the Xpdf makefiles. * Type 'make'. This should build the executables: xpdf/xpdf xpdf/pdftops xpdf/pdftotext xpdf/pdfinfo xpdf/pdffonts xpdf/pdfdetach xpdf/pdftoppm xpdf/pdfimages * If desired, type 'make install' to install the binaries and man pages. The old Makefile.config and Makefiles are no longer provided or supported. If you really want to manually configure Xpdf (which is not recommended), the files that need to be created are aconf.h, Makefile, goo/Makefile, fofi/Makefile, splash/Makefile, and xpdf/Makefile, all of which are generated from the corresponding '.in' files. If you want to run a quick test, there is a tiny PDF file included with xpdf, as misc/hello.pdf . ************* *** VMS *** ************* * The 'stddef.h' include file which comes with older versions of gcc may be missing a definition for wchar_t. In this case, add the following lines: ----- File GNU_CC:[INCLUDE]STDDEF.H;2 44 /* Wide characters, not yet supported by VAXCRTL [match VAXC's /* * Use A4 paper size instead of Letter for PostScript output. */ #undef A4_PAPER /* * Do not allow text selection. */ #undef NO_TEXT_SELECT /* * Include support for OPI comments. */ #undef OPI_SUPPORT /* * Enable multithreading support. */ #define MULTITHREADED 1 /* * Enable C++ exceptions. */ #define USE_EXCEPTIONS 1 /* * Enable word list support. */ #undef TEXTOUT_WORD_LIST /* * Use fixed point (instead of floating point) arithmetic. */ #undef USE_FIXEDPOINT /* * Directory with the Xpdf app-defaults file. */ #undef APPDEFDIR /* * Full path for the system-wide xpdfrc file. */ #undef SYSTEM_XPDFRC /* * Various include files and functions. */ #undef HAVE_DIRENT_H #undef HAVE_SYS_NDIR_H #undef HAVE_SYS_DIR_H #undef HAVE_NDIR_H #undef HAVE_SYS_SELECT_H #undef HAVE_SYS_BSDTYPES_H #undef HAVE_STRINGS_H #undef HAVE_BSTRING_H #undef HAVE_POPEN #undef HAVE_MKSTEMP #undef HAVE_MKSTEMPS #undef SELECT_TAKES_INT #define HAVE_STD_SORT 1 #undef HAVE_FSEEKO #undef HAVE_FSEEK64 #undef _FILE_OFFSET_BITS #undef _LARGE_FILES #undef _LARGEFILE_SOURCE #undef HAVE_XTAPPSETEXITFLAG /* * This is defined if using libXpm. */ #undef HAVE_X11_XPM_H /* * This is defined if using t1lib. */ #undef HAVE_T1LIB_H /* * One of these is defined if using FreeType (version 1 or 2). */ #undef HAVE_FREETYPE_H #define HAVE_FREETYPE_FREETYPE_H 1 /* * This is defined if using FreeType version 2. */ #define FREETYPE2 /* * This is defined if using libpaper. */ #undef HAVE_PAPER_H /* * Enable support for loading plugins. */ #undef ENABLE_PLUGINS /* * Defined if the Splash library is avaiable. */ #undef HAVE_SPLASH /* * Enable support for CMYK output. */ #undef SPLASH_CMYK #endif xpdf-3.03/configure0000755000076400007640000075032111622305345013632 0ustar dereknderekn#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.65. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, # Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME= PACKAGE_TARNAME= PACKAGE_VERSION= PACKAGE_STRING= PACKAGE_BUGREPORT= PACKAGE_URL= ac_unique_file="xpdf/Gfx.cc" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='LTLIBOBJS LIBOBJS XPDF_TARGET X libpaper_CFLAGS libpaper_LIBS freetype2_CFLAGS freetype2_LIBS t1_CFLAGS t1_LIBS Sgm_CFLAGS Sgm_LIBS Xm_CFLAGS Xm_LIBS Xt_CFLAGS Xt_LIBS Xp_CFLAGS Xp_LIBS Xext_CFLAGS Xext_LIBS Xpm_CFLAGS Xpm_LIBS EGREP GREP X_EXTRA_LIBS X_LIBS X_PRE_LIBS X_CFLAGS CPP XMKMF UP_DIR AR LIBPREFIX EXE RANLIB INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_a4_paper enable_no_text_select enable_opi enable_multithreaded enable_exceptions enable_wordlist enable_fixedpoint enable_cmyk with_appdef_dir with_x enable_largefile with_Xpm_library with_Xpm_includes with_Xext_library with_Xext_includes with_Xp_library with_Xp_includes with_Xt_library with_Xt_includes with_Xm_library with_Xm_includes with_Sgm_library with_Sgm_includes with_freetype2_library with_freetype2_includes with_libpaper_library with_libpaper_includes ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC XMKMF CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error "unrecognized option: \`$ac_option' Try \`$0 --help' for more information." ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used." >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures this package to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF X features: --x-includes=DIR X include files are in DIR --x-libraries=DIR X library files are in DIR _ACEOF fi if test -n "$ac_init_help"; then cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-a4-paper use A4 paper size instead of Letter for PostScript output --enable-no-text-select do not allow text selection --enable-opi include support for OPI comments --enable-multithreaded include support for multithreading --enable-exceptions use C++ exceptions --enable-wordlist include support for building word lists --enable-fixedpoint use fixed point (instead of floating point) arithmetic --enable-cmyk include support for CMYK rasterization --disable-largefile omit support for large files Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-appdef-dir set app-defaults directory --with-x use the X Window System --with-Xpm-library=PATH use Xpm library (pixmap library - used only for icon) --with-Xpm-includes=DIR set directory for Xpm headers --with-Xext-library=PATH use Xext library (Motif library) --with-Xext-includes=DIR set directory for Xext headers --with-Xp-library=PATH use Xp library (Motif library) --with-Xp-includes=DIR set directory for Xp headers --with-Xt-library=PATH use Xt library (Motif library) --with-Xt-includes=DIR set directory for Xt headers --with-Xm-library=PATH use Xm library (Motif library) --with-Xm-includes=DIR set directory for Xm headers --with-Sgm-library=PATH use Sgm library (SGI Motif library) --with-Sgm-includes=DIR set directory for Sgm headers --with-freetype2-library=PATH use freetype2 library (FreeType2 font rasterizer - version 2.0.5+) --with-freetype2-includes=DIR set directory for freetype2 headers --with-libpaper-library=PATH use libpaper library (Debian libpaper) --with-libpaper-includes=DIR set directory for libpaper headers Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CXX C++ compiler command CXXFLAGS C++ compiler flags XMKMF Path to xmkmf, Makefile generator for X Window System CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF configure generated by GNU Autoconf 2.65 Copyright (C) 2009 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } >/dev/null && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_func # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_cxx_check_func LINENO FUNC VAR # ------------------------------------ # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_cxx_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_cxx_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_mongrel # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by $as_me, which was generated by GNU Autoconf 2.65. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo cat <<\_ASBOX ## ---------------- ## ## Cache variables. ## ## ---------------- ## _ASBOX echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo cat <<\_ASBOX ## ----------------- ## ## Output variables. ## ## ----------------- ## _ASBOX echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then cat <<\_ASBOX ## ------------------- ## ## File substitutions. ## ## ------------------- ## _ASBOX echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then cat <<\_ASBOX ## ----------- ## ## confdefs.h. ## ## ----------- ## _ASBOX echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then ac_site_file1=$CONFIG_SITE elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers aconf.h" # Check whether --enable-a4-paper was given. if test "${enable_a4_paper+set}" = set; then : enableval=$enable_a4_paper; $as_echo "#define A4_PAPER 1" >>confdefs.h fi # Check whether --enable-no-text-select was given. if test "${enable_no_text_select+set}" = set; then : enableval=$enable_no_text_select; $as_echo "#define NO_TEXT_SELECT 1" >>confdefs.h fi # Check whether --enable-opi was given. if test "${enable_opi+set}" = set; then : enableval=$enable_opi; $as_echo "#define OPI_SUPPORT 1" >>confdefs.h fi # Check whether --enable-multithreaded was given. if test "${enable_multithreaded+set}" = set; then : enableval=$enable_multithreaded; $as_echo "#define MULTITHREADED 1" >>confdefs.h fi # Check whether --enable-exceptions was given. if test "${enable_exceptions+set}" = set; then : enableval=$enable_exceptions; $as_echo "#define USE_EXCEPTIONS 1" >>confdefs.h fi # Check whether --enable-wordlist was given. if test "${enable_wordlist+set}" = set; then : enableval=$enable_wordlist; $as_echo "#define TEXTOUT_WORD_LIST 1" >>confdefs.h fi # Check whether --enable-fixedpoint was given. if test "${enable_fixedpoint+set}" = set; then : enableval=$enable_fixedpoint; $as_echo "#define USE_FIXEDPOINT 1" >>confdefs.h fi # Check whether --enable-cmyk was given. if test "${enable_cmyk+set}" = set; then : enableval=$enable_cmyk; $as_echo "#define SPLASH_CMYK 1" >>confdefs.h fi # Check whether --with-appdef-dir was given. if test "${with_appdef_dir+set}" = set; then : withval=$with_appdef_dir; cat >>confdefs.h <<_ACEOF #define APPDEFDIR "$with_appdef_dir" _ACEOF fi if test "$sysconfdir" = '${prefix}/etc'; then if test "x$prefix" = xNONE; then system_xpdfrc="$ac_default_prefix/etc/xpdfrc" else system_xpdfrc="$prefix/etc/xpdfrc" fi else system_xpdfrc="$sysconfdir/xpdfrc" fi cat >>confdefs.h <<_ACEOF #define SYSTEM_XPDFRC "$system_xpdfrc" _ACEOF ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "no acceptable C compiler found in \$PATH See \`config.log' for more details." "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { as_fn_set_status 77 as_fn_error "C compiler cannot create executables See \`config.log' for more details." "$LINENO" 5; }; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details." "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if test "${ac_cv_objext+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "cannot compute suffix of object files: cannot compile See \`config.log' for more details." "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if test "${ac_cv_c_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if test "${ac_cv_prog_cc_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing strerror" >&5 $as_echo_n "checking for library containing strerror... " >&6; } if test "${ac_cv_search_strerror+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char strerror (); int main () { return strerror (); ; return 0; } _ACEOF for ac_lib in '' cposix; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_strerror=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_strerror+set}" = set; then : break fi done if test "${ac_cv_search_strerror+set}" = set; then : else ac_cv_search_strerror=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_strerror" >&5 $as_echo "$ac_cv_search_strerror" >&6; } ac_res=$ac_cv_search_strerror if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi case $ac_cv_prog_cc_stdc in #( no) : ac_cv_prog_cc_c99=no; ac_cv_prog_cc_c89=no ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C99" >&5 $as_echo_n "checking for $CC option to accept ISO C99... " >&6; } if test "${ac_cv_prog_cc_c99+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c99=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include // Check varargs macros. These examples are taken from C99 6.10.3.5. #define debug(...) fprintf (stderr, __VA_ARGS__) #define showlist(...) puts (#__VA_ARGS__) #define report(test,...) ((test) ? puts (#test) : printf (__VA_ARGS__)) static void test_varargs_macros (void) { int x = 1234; int y = 5678; debug ("Flag"); debug ("X = %d\n", x); showlist (The first, second, and third items.); report (x>y, "x is %d but y is %d", x, y); } // Check long long types. #define BIG64 18446744073709551615ull #define BIG32 4294967295ul #define BIG_OK (BIG64 / BIG32 == 4294967297ull && BIG64 % BIG32 == 0) #if !BIG_OK your preprocessor is broken; #endif #if BIG_OK #else your preprocessor is broken; #endif static long long int bignum = -9223372036854775807LL; static unsigned long long int ubignum = BIG64; struct incomplete_array { int datasize; double data[]; }; struct named_init { int number; const wchar_t *name; double average; }; typedef const char *ccp; static inline int test_restrict (ccp restrict text) { // See if C++-style comments work. // Iterate through items via the restricted pointer. // Also check for declarations in for loops. for (unsigned int i = 0; *(text+i) != '\0'; ++i) continue; return 0; } // Check varargs and va_copy. static void test_varargs (const char *format, ...) { va_list args; va_start (args, format); va_list args_copy; va_copy (args_copy, args); const char *str; int number; float fnumber; while (*format) { switch (*format++) { case 's': // string str = va_arg (args_copy, const char *); break; case 'd': // int number = va_arg (args_copy, int); break; case 'f': // float fnumber = va_arg (args_copy, double); break; default: break; } } va_end (args_copy); va_end (args); } int main () { // Check bool. _Bool success = false; // Check restrict. if (test_restrict ("String literal") == 0) success = true; char *restrict newvar = "Another string"; // Check varargs. test_varargs ("s, d' f .", "string", 65, 34.234); test_varargs_macros (); // Check flexible array members. struct incomplete_array *ia = malloc (sizeof (struct incomplete_array) + (sizeof (double) * 10)); ia->datasize = 10; for (int i = 0; i < ia->datasize; ++i) ia->data[i] = i * 1.234; // Check named initializers. struct named_init ni = { .number = 34, .name = L"Test wide string", .average = 543.34343, }; ni.number = 58; int dynamic_array[ni.number]; dynamic_array[ni.number - 1] = 543; // work around unused variable warnings return (!success || bignum == 0LL || ubignum == 0uLL || newvar[0] == 'x' || dynamic_array[ni.number - 1] != 543); ; return 0; } _ACEOF for ac_arg in '' -std=gnu99 -std=c99 -c99 -AC99 -xc99=all -qlanglvl=extc99 do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c99=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c99" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c99" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c99" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c99" >&5 $as_echo "$ac_cv_prog_cc_c99" >&6; } ;; esac if test "x$ac_cv_prog_cc_c99" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c99 else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if test "${ac_cv_prog_cc_c89+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : ac_cv_prog_cc_stdc=$ac_cv_prog_cc_c89 else ac_cv_prog_cc_stdc=no fi fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO Standard C" >&5 $as_echo_n "checking for $CC option to accept ISO Standard C... " >&6; } if test "${ac_cv_prog_cc_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 fi case $ac_cv_prog_cc_stdc in #( no) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; #( '') : { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; #( *) : { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_stdc" >&5 $as_echo "$ac_cv_prog_cc_stdc" >&6; } ;; esac #if test -z "$CXX" -a "$CC" = "gcc"; then # CXX="gcc" #fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if test "${ac_cv_prog_cxx_g+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do for ac_t in install-sh install.sh shtool; do if test -f "$ac_dir/$ac_t"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/$ac_t -c" break 2 fi done done if test -z "$ac_aux_dir"; then as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if test "${ac_cv_path_install+set}" = set; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi EXE="" LIBPREFIX="lib" AR="ar rc" UP_DIR="" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OS/2 (with EMX)" >&5 $as_echo_n "checking for OS/2 (with EMX)... " >&6; } if test "${xpdf_cv_sys_os2+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __EMX__ ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : xpdf_cv_sys_os2=yes else xpdf_cv_sys_os2=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_sys_os2" >&5 $as_echo "$xpdf_cv_sys_os2" >&6; } if test "$xpdf_cv_sys_os2" = yes; then EXE=".exe" LIBPREFIX="" AR="ar -rc" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DOS (with DJGPP)" >&5 $as_echo_n "checking for DOS (with DJGPP)... " >&6; } if test "${xpdf_cv_sys_dos+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { __DJGPP__ ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : xpdf_cv_sys_dos=yes else xpdf_cv_sys_dos=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_sys_dos" >&5 $as_echo "$xpdf_cv_sys_dos" >&6; } if test "$xpdf_cv_sys_dos" = yes; then EXE=".exe" LIBPREFIX="lib" AR="ar -rc" UP_DIR="../" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if test "${ac_cv_prog_CPP+set}" = set; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details." "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for X" >&5 $as_echo_n "checking for X... " >&6; } # Check whether --with-x was given. if test "${with_x+set}" = set; then : withval=$with_x; fi # $have_x is `yes', `no', `disabled', or empty when we do not yet know. if test "x$with_x" = xno; then # The user explicitly disabled X. have_x=disabled else case $x_includes,$x_libraries in #( *\'*) as_fn_error "cannot use X directory names containing '" "$LINENO" 5;; #( *,NONE | NONE,*) if test "${ac_cv_have_x+set}" = set; then : $as_echo_n "(cached) " >&6 else # One or both of the vars are not set, and there is no cached value. ac_x_includes=no ac_x_libraries=no rm -f -r conftest.dir if mkdir conftest.dir; then cd conftest.dir cat >Imakefile <<'_ACEOF' incroot: @echo incroot='${INCROOT}' usrlibdir: @echo usrlibdir='${USRLIBDIR}' libdir: @echo libdir='${LIBDIR}' _ACEOF if (export CC; ${XMKMF-xmkmf}) >/dev/null 2>/dev/null && test -f Makefile; then # GNU make sometimes prints "make[1]: Entering...", which would confuse us. for ac_var in incroot usrlibdir libdir; do eval "ac_im_$ac_var=\`\${MAKE-make} $ac_var 2>/dev/null | sed -n 's/^$ac_var=//p'\`" done # Open Windows xmkmf reportedly sets LIBDIR instead of USRLIBDIR. for ac_extension in a so sl dylib la dll; do if test ! -f "$ac_im_usrlibdir/libX11.$ac_extension" && test -f "$ac_im_libdir/libX11.$ac_extension"; then ac_im_usrlibdir=$ac_im_libdir; break fi done # Screen out bogus values from the imake configuration. They are # bogus both because they are the default anyway, and because # using them would break gcc on systems where it needs fixed includes. case $ac_im_incroot in /usr/include) ac_x_includes= ;; *) test -f "$ac_im_incroot/X11/Xos.h" && ac_x_includes=$ac_im_incroot;; esac case $ac_im_usrlibdir in /usr/lib | /usr/lib64 | /lib | /lib64) ;; *) test -d "$ac_im_usrlibdir" && ac_x_libraries=$ac_im_usrlibdir ;; esac fi cd .. rm -f -r conftest.dir fi # Standard set of common directories for X headers. # Check X11 before X11Rn because it is often a symlink to the current release. ac_x_header_dirs=' /usr/X11/include /usr/X11R7/include /usr/X11R6/include /usr/X11R5/include /usr/X11R4/include /usr/include/X11 /usr/include/X11R7 /usr/include/X11R6 /usr/include/X11R5 /usr/include/X11R4 /usr/local/X11/include /usr/local/X11R7/include /usr/local/X11R6/include /usr/local/X11R5/include /usr/local/X11R4/include /usr/local/include/X11 /usr/local/include/X11R7 /usr/local/include/X11R6 /usr/local/include/X11R5 /usr/local/include/X11R4 /usr/X386/include /usr/x386/include /usr/XFree86/include/X11 /usr/include /usr/local/include /usr/unsupported/include /usr/athena/include /usr/local/x11r5/include /usr/lpp/Xamples/include /usr/openwin/include /usr/openwin/share/include' if test "$ac_x_includes" = no; then # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # We can compile using X headers with no special include directory. ac_x_includes= else for ac_dir in $ac_x_header_dirs; do if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi done fi rm -f conftest.err conftest.$ac_ext fi # $ac_x_includes = no if test "$ac_x_libraries" = no; then # Check for the libraries. # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS LIBS="-lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { XrmInitialize () ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : LIBS=$ac_save_LIBS # We can link X programs with no special library path. ac_x_libraries= else LIBS=$ac_save_LIBS for ac_dir in `$as_echo "$ac_x_includes $ac_x_header_dirs" | sed s/include/lib/g` do # Don't even attempt the hair of trying to link an X program! for ac_extension in a so sl dylib la dll; do if test -r "$ac_dir/libX11.$ac_extension"; then ac_x_libraries=$ac_dir break 2 fi done done fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi # $ac_x_libraries = no case $ac_x_includes,$ac_x_libraries in #( no,* | *,no | *\'*) # Didn't find X, or a directory has "'" in its name. ac_cv_have_x="have_x=no";; #( *) # Record where we found X for the cache. ac_cv_have_x="have_x=yes\ ac_x_includes='$ac_x_includes'\ ac_x_libraries='$ac_x_libraries'" esac fi ;; #( *) have_x=yes;; esac eval "$ac_cv_have_x" fi # $with_x != no if test "$have_x" != yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_x" >&5 $as_echo "$have_x" >&6; } no_x=yes else # If each of the values was on the command line, it overrides each guess. test "x$x_includes" = xNONE && x_includes=$ac_x_includes test "x$x_libraries" = xNONE && x_libraries=$ac_x_libraries # Update the cache value to reflect the command line values. ac_cv_have_x="have_x=yes\ ac_x_includes='$x_includes'\ ac_x_libraries='$x_libraries'" { $as_echo "$as_me:${as_lineno-$LINENO}: result: libraries $x_libraries, headers $x_includes" >&5 $as_echo "libraries $x_libraries, headers $x_includes" >&6; } fi if test "$no_x" = yes; then # Not all programs may use this symbol, but it does not hurt to define it. $as_echo "#define X_DISPLAY_MISSING 1" >>confdefs.h X_CFLAGS= X_PRE_LIBS= X_LIBS= X_EXTRA_LIBS= else if test -n "$x_includes"; then X_CFLAGS="$X_CFLAGS -I$x_includes" fi # It would also be nice to do this for all -L options, not just this one. if test -n "$x_libraries"; then X_LIBS="$X_LIBS -L$x_libraries" # For Solaris; some versions of Sun CC require a space after -R and # others require no space. Words are not sufficient . . . . { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -R must be followed by a space" >&5 $as_echo_n "checking whether -R must be followed by a space... " >&6; } ac_xsave_LIBS=$LIBS; LIBS="$LIBS -R$x_libraries" ac_xsave_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } X_LIBS="$X_LIBS -R$x_libraries" else LIBS="$ac_xsave_LIBS -R $x_libraries" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } X_LIBS="$X_LIBS -R $x_libraries" else { $as_echo "$as_me:${as_lineno-$LINENO}: result: neither works" >&5 $as_echo "neither works" >&6; } fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_c_werror_flag=$ac_xsave_c_werror_flag LIBS=$ac_xsave_LIBS fi # Check for system-dependent libraries X programs must link with. # Do this before checking for the system-independent R6 libraries # (-lICE), since we may need -lsocket or whatever for X linking. if test "$ISC" = yes; then X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl_s -linet" else # Martyn Johnson says this is needed for Ultrix, if the X # libraries were built with DECnet support. And Karl Berry says # the Alpha needs dnet_stub (dnet does not exist). ac_xsave_LIBS="$LIBS"; LIBS="$LIBS $X_LIBS -lX11" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XOpenDisplay (); int main () { return XOpenDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet... " >&6; } if test "${ac_cv_lib_dnet_dnet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_dnet_ntoa=yes else ac_cv_lib_dnet_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_dnet_ntoa" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet" fi if test $ac_cv_lib_dnet_dnet_ntoa = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dnet_ntoa in -ldnet_stub" >&5 $as_echo_n "checking for dnet_ntoa in -ldnet_stub... " >&6; } if test "${ac_cv_lib_dnet_stub_dnet_ntoa+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldnet_stub $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dnet_ntoa (); int main () { return dnet_ntoa (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dnet_stub_dnet_ntoa=yes else ac_cv_lib_dnet_stub_dnet_ntoa=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dnet_stub_dnet_ntoa" >&5 $as_echo "$ac_cv_lib_dnet_stub_dnet_ntoa" >&6; } if test "x$ac_cv_lib_dnet_stub_dnet_ntoa" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -ldnet_stub" fi fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS="$ac_xsave_LIBS" # msh@cis.ufl.edu says -lnsl (and -lsocket) are needed for his 386/AT, # to get the SysV transport functions. # Chad R. Larson says the Pyramis MIS-ES running DC/OSx (SVR4) # needs -lnsl. # The nsl library prevents programs from opening the X display # on Irix 5.2, according to T.E. Dickey. # The functions gethostbyname, getservbyname, and inet_addr are # in -lbsd on LynxOS 3.0.1/i386, according to Lars Hecking. ac_fn_c_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lnsl" >&5 $as_echo_n "checking for gethostbyname in -lnsl... " >&6; } if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_nsl_gethostbyname=yes else ac_cv_lib_nsl_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_gethostbyname" >&5 $as_echo "$ac_cv_lib_nsl_gethostbyname" >&6; } if test "x$ac_cv_lib_nsl_gethostbyname" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lnsl" fi if test $ac_cv_lib_nsl_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi fi # lieder@skyler.mavd.honeywell.com says without -lsocket, # socket/setsockopt and other routines are undefined under SCO ODT # 2.0. But -lsocket is broken on IRIX 5.2 (and is not necessary # on later versions), says Simon Leinen: it contains gethostby* # variants that don't use the name server (or something). -lsocket # must be given before -lnsl if both are needed. We assume that # if connect needs -lnsl, so does gethostbyname. ac_fn_c_check_func "$LINENO" "connect" "ac_cv_func_connect" if test "x$ac_cv_func_connect" = x""yes; then : fi if test $ac_cv_func_connect = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for connect in -lsocket" >&5 $as_echo_n "checking for connect in -lsocket... " >&6; } if test "${ac_cv_lib_socket_connect+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char connect (); int main () { return connect (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_socket_connect=yes else ac_cv_lib_socket_connect=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_connect" >&5 $as_echo "$ac_cv_lib_socket_connect" >&6; } if test "x$ac_cv_lib_socket_connect" = x""yes; then : X_EXTRA_LIBS="-lsocket $X_EXTRA_LIBS" fi fi # Guillermo Gomez says -lposix is necessary on A/UX. ac_fn_c_check_func "$LINENO" "remove" "ac_cv_func_remove" if test "x$ac_cv_func_remove" = x""yes; then : fi if test $ac_cv_func_remove = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for remove in -lposix" >&5 $as_echo_n "checking for remove in -lposix... " >&6; } if test "${ac_cv_lib_posix_remove+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char remove (); int main () { return remove (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_posix_remove=yes else ac_cv_lib_posix_remove=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_posix_remove" >&5 $as_echo "$ac_cv_lib_posix_remove" >&6; } if test "x$ac_cv_lib_posix_remove" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lposix" fi fi # BSDI BSD/OS 2.1 needs -lipc for XOpenDisplay. ac_fn_c_check_func "$LINENO" "shmat" "ac_cv_func_shmat" if test "x$ac_cv_func_shmat" = x""yes; then : fi if test $ac_cv_func_shmat = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shmat in -lipc" >&5 $as_echo_n "checking for shmat in -lipc... " >&6; } if test "${ac_cv_lib_ipc_shmat+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lipc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shmat (); int main () { return shmat (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ipc_shmat=yes else ac_cv_lib_ipc_shmat=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ipc_shmat" >&5 $as_echo "$ac_cv_lib_ipc_shmat" >&6; } if test "x$ac_cv_lib_ipc_shmat" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lipc" fi fi fi # Check for libraries that X11R6 Xt/Xaw programs need. ac_save_LDFLAGS=$LDFLAGS test -n "$x_libraries" && LDFLAGS="$LDFLAGS -L$x_libraries" # SM needs ICE to (dynamically) link under SunOS 4.x (so we have to # check for ICE first), but we must link in the order -lSM -lICE or # we get undefined symbols. So assume we have SM if we have ICE. # These have to be linked with before -lX11, unlike the other # libraries we check for below, so use a different variable. # John Interrante, Karl Berry { $as_echo "$as_me:${as_lineno-$LINENO}: checking for IceConnectionNumber in -lICE" >&5 $as_echo_n "checking for IceConnectionNumber in -lICE... " >&6; } if test "${ac_cv_lib_ICE_IceConnectionNumber+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lICE $X_EXTRA_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char IceConnectionNumber (); int main () { return IceConnectionNumber (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_ICE_IceConnectionNumber=yes else ac_cv_lib_ICE_IceConnectionNumber=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ICE_IceConnectionNumber" >&5 $as_echo "$ac_cv_lib_ICE_IceConnectionNumber" >&6; } if test "x$ac_cv_lib_ICE_IceConnectionNumber" = x""yes; then : X_PRE_LIBS="$X_PRE_LIBS -lSM -lICE" fi LDFLAGS=$ac_save_LDFLAGS fi ac_header_dirent=no for ac_hdr in dirent.h sys/ndir.h sys/dir.h ndir.h; do as_ac_Header=`$as_echo "ac_cv_header_dirent_$ac_hdr" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_hdr that defines DIR" >&5 $as_echo_n "checking for $ac_hdr that defines DIR... " >&6; } if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include <$ac_hdr> int main () { if ((DIR *) 0) return 0; ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$as_ac_Header=yes" else eval "$as_ac_Header=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$as_ac_Header { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval as_val=\$$as_ac_Header if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_hdr" | $as_tr_cpp` 1 _ACEOF ac_header_dirent=$ac_hdr; break fi done # Two versions of opendir et al. are in -ldir and -lx on SCO Xenix. if test $ac_header_dirent = dirent.h; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' dir; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing opendir" >&5 $as_echo_n "checking for library containing opendir... " >&6; } if test "${ac_cv_search_opendir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_func_search_save_LIBS=$LIBS cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char opendir (); int main () { return opendir (); ; return 0; } _ACEOF for ac_lib in '' x; do if test -z "$ac_lib"; then ac_res="none required" else ac_res=-l$ac_lib LIBS="-l$ac_lib $ac_func_search_save_LIBS" fi if ac_fn_c_try_link "$LINENO"; then : ac_cv_search_opendir=$ac_res fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext if test "${ac_cv_search_opendir+set}" = set; then : break fi done if test "${ac_cv_search_opendir+set}" = set; then : else ac_cv_search_opendir=no fi rm conftest.$ac_ext LIBS=$ac_func_search_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_opendir" >&5 $as_echo "$ac_cv_search_opendir" >&6; } ac_res=$ac_cv_search_opendir if test "$ac_res" != no; then : test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" fi fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu ac_fn_cxx_check_func "$LINENO" "gethostbyname" "ac_cv_func_gethostbyname" if test "x$ac_cv_func_gethostbyname" = x""yes; then : fi if test $ac_cv_func_gethostbyname = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for gethostbyname in -lbsd" >&5 $as_echo_n "checking for gethostbyname in -lbsd... " >&6; } if test "${ac_cv_lib_bsd_gethostbyname+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lbsd $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char gethostbyname (); int main () { return gethostbyname (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_bsd_gethostbyname=yes else ac_cv_lib_bsd_gethostbyname=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_bsd_gethostbyname" >&5 $as_echo "$ac_cv_lib_bsd_gethostbyname" >&6; } if test "x$ac_cv_lib_bsd_gethostbyname" = x""yes; then : X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking select() and fd_set in sys/select.h and sys/bsdtypes.h" >&5 $as_echo_n "checking select() and fd_set in sys/select.h and sys/bsdtypes.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { fd_set fds; select(0, NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not needed" >&5 $as_echo "not needed" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include int main () { fd_set fds; select(0, NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then $as_echo "#define HAVE_SYS_SELECT_H 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: need sys/select.h" >&5 $as_echo "need sys/select.h" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include #include int main () { fd_set fds; select(0, NULL, NULL, NULL, NULL); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then $as_echo "#define HAVE_SYS_BSDTYPES_H 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: need sys/bsdtypes.h" >&5 $as_echo "need sys/bsdtypes.h" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: problem" >&5 $as_echo "problem" >&6; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking FD_ZERO and strings.h or bstring.h" >&5 $as_echo_n "checking FD_ZERO and strings.h or bstring.h... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #ifdef HAVE_SYS_SELECT_H #include #endif int main () { fd_set fds; FD_ZERO(&fds); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not needed" >&5 $as_echo "not needed" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif int main () { fd_set fds; FD_ZERO(&fds); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then $as_echo "#define HAVE_STRINGS_H 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: need strings.h" >&5 $as_echo "need strings.h" >&6; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif int main () { fd_set fds; FD_ZERO(&fds); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_ok=yes else xpdf_ok=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $xpdf_ok = yes; then $as_echo "#define HAVE_BSTRING_H 1" >>confdefs.h { $as_echo "$as_me:${as_lineno-$LINENO}: result: need bstring.h" >&5 $as_echo "need bstring.h" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: problem" >&5 $as_echo "problem" >&6; } fi fi fi for ac_func in rewinddir do : ac_fn_cxx_check_func "$LINENO" "rewinddir" "ac_cv_func_rewinddir" if test "x$ac_cv_func_rewinddir" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_REWINDDIR 1 _ACEOF fi done if test $ac_cv_func_rewinddir = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for rewinddir in -lcposix" >&5 $as_echo_n "checking for rewinddir in -lcposix... " >&6; } if test "${ac_cv_lib_cposix_rewinddir+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lcposix $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char rewinddir (); int main () { return rewinddir (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_cposix_rewinddir=yes else ac_cv_lib_cposix_rewinddir=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cposix_rewinddir" >&5 $as_echo "$ac_cv_lib_cposix_rewinddir" >&6; } if test "x$ac_cv_lib_cposix_rewinddir" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBCPOSIX 1 _ACEOF LIBS="-lcposix $LIBS" fi fi for ac_func in popen do : ac_fn_cxx_check_func "$LINENO" "popen" "ac_cv_func_popen" if test "x$ac_cv_func_popen" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_POPEN 1 _ACEOF fi done { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mkstemp" >&5 $as_echo_n "checking for mkstemp... " >&6; } if test "${xpdf_cv_func_mkstemp+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { mkstemp("foo"); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : xpdf_cv_func_mkstemp=yes else xpdf_cv_func_mkstemp=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_func_mkstemp" >&5 $as_echo "$xpdf_cv_func_mkstemp" >&6; } if test "$xpdf_cv_func_mkstemp" = yes; then $as_echo "#define HAVE_MKSTEMP 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for mkstemps" >&5 $as_echo_n "checking for mkstemps... " >&6; } if test "${xpdf_cv_func_mkstemps+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include int main () { mkstemps("foo", 0); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : xpdf_cv_func_mkstemps=yes else xpdf_cv_func_mkstemps=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_func_mkstemps" >&5 $as_echo "$xpdf_cv_func_mkstemps" >&6; } if test "$xpdf_cv_func_mkstemps" = yes; then $as_echo "#define HAVE_MKSTEMPS 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether select takes fd_set arguments" >&5 $as_echo_n "checking whether select takes fd_set arguments... " >&6; } if test "${xpdf_cv_func_select_arg+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif int main () { fd_set fds; select(1, &fds, &fds, &fds, 0); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_cv_func_select_arg=yes else xpdf_cv_func_select_arg=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_func_select_arg" >&5 $as_echo "$xpdf_cv_func_select_arg" >&6; } if test "$xpdf_cv_func_select_arg" != yes; then $as_echo "#define SELECT_TAKES_INT 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for std::sort" >&5 $as_echo_n "checking for std::sort... " >&6; } if test "${xpdf_cv_func_std_sort+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include struct functor { bool operator()(const int &i0, const int &i1) { return i0 < i1; } }; int main () { int a[100]; std::sort(a, a+100, functor()); ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : xpdf_cv_func_std_sort=yes else xpdf_cv_func_std_sort=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xpdf_cv_func_std_sort" >&5 $as_echo "$xpdf_cv_func_std_sort" >&6; } if test "$xpdf_cv_func_std_sort" = yes; then $as_echo "#define HAVE_STD_SORT 1" >>confdefs.h fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Check whether --enable-largefile was given. if test "${enable_largefile+set}" = set; then : enableval=$enable_largefile; fi if test "$enable_largefile" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for special C compiler options needed for large files" >&5 $as_echo_n "checking for special C compiler options needed for large files... " >&6; } if test "${ac_cv_sys_largefile_CC+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_cv_sys_largefile_CC=no if test "$GCC" != yes; then ac_save_CC=$CC while :; do # IRIX 6.2 and later do not support large files by default, # so use the C compiler's -n32 option if that helps. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : break fi rm -f core conftest.err conftest.$ac_objext CC="$CC -n32" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_largefile_CC=' -n32'; break fi rm -f core conftest.err conftest.$ac_objext break done CC=$ac_save_CC rm -f conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_CC" >&5 $as_echo "$ac_cv_sys_largefile_CC" >&6; } if test "$ac_cv_sys_largefile_CC" != no; then CC=$CC$ac_cv_sys_largefile_CC fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _FILE_OFFSET_BITS value needed for large files" >&5 $as_echo_n "checking for _FILE_OFFSET_BITS value needed for large files... " >&6; } if test "${ac_cv_sys_file_offset_bits+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _FILE_OFFSET_BITS 64 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_file_offset_bits=64; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_file_offset_bits=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_file_offset_bits" >&5 $as_echo "$ac_cv_sys_file_offset_bits" >&6; } case $ac_cv_sys_file_offset_bits in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits _ACEOF ;; esac rm -rf conftest* if test $ac_cv_sys_file_offset_bits = unknown; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGE_FILES value needed for large files" >&5 $as_echo_n "checking for _LARGE_FILES value needed for large files... " >&6; } if test "${ac_cv_sys_large_files+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=no; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGE_FILES 1 #include /* Check that off_t can represent 2**63 - 1 correctly. We can't simply define LARGE_OFF_T to be 9223372036854775807, since some C++ compilers masquerading as C compilers incorrectly reject 9223372036854775807. */ #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 && LARGE_OFF_T % 2147483647 == 1) ? 1 : -1]; int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_sys_large_files=1; break fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_sys_large_files=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_large_files" >&5 $as_echo "$ac_cv_sys_large_files" >&6; } case $ac_cv_sys_large_files in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGE_FILES $ac_cv_sys_large_files _ACEOF ;; esac rm -rf conftest* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for _LARGEFILE_SOURCE value needed for large files" >&5 $as_echo_n "checking for _LARGEFILE_SOURCE value needed for large files... " >&6; } if test "${ac_cv_sys_largefile_source+set}" = set; then : $as_echo_n "(cached) " >&6 else while :; do cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=no; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define _LARGEFILE_SOURCE 1 #include /* for off_t */ #include int main () { int (*fp) (FILE *, off_t, int) = fseeko; return fseeko (stdin, 0, 0) && fp (stdin, 0, 0); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_sys_largefile_source=1; break fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_cv_sys_largefile_source=unknown break done fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sys_largefile_source" >&5 $as_echo "$ac_cv_sys_largefile_source" >&6; } case $ac_cv_sys_largefile_source in #( no | unknown) ;; *) cat >>confdefs.h <<_ACEOF #define _LARGEFILE_SOURCE $ac_cv_sys_largefile_source _ACEOF ;; esac rm -rf conftest* # We used to try defining _XOPEN_SOURCE=500 too, to work around a bug # in glibc 2.1.3, but that breaks too many other things. # If you want fseeko and ftello with glibc, upgrade to a fixed glibc. if test $ac_cv_sys_largefile_source != unknown; then $as_echo "#define HAVE_FSEEKO 1" >>confdefs.h fi for ac_func in fseek64 do : ac_fn_c_check_func "$LINENO" "fseek64" "ac_cv_func_fseek64" if test "x$ac_cv_func_fseek64" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FSEEK64 1 _ACEOF xpdf_cv_func_fseek64=yes else xpdf_cv_func_fseek64=no fi done for ac_func in ftell64 do : ac_fn_c_check_func "$LINENO" "ftell64" "ac_cv_func_ftell64" if test "x$ac_cv_func_ftell64" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FTELL64 1 _ACEOF xpdf_cv_func_ftell64=yes else xpdf_cv_func_ftell64=no fi done if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then $as_echo "#define HAVE_FSEEK64 1" >>confdefs.h fi if test -z "$no_x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if test "${ac_cv_path_GREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if test "${ac_cv_path_EGREP+set}" = set; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if test "${ac_cv_header_stdc+set}" = set; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " eval as_val=\$$as_ac_Header if test "x$as_val" = x""yes; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done # Check whether --with-Xpm-library was given. if test "${with_Xpm_library+set}" = set; then : withval=$with_Xpm_library; smr_cv_with_Xpm_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Xpm library" >&5 $as_echo_n "checking whether to use Xpm library... " >&6; } if test "${smr_cv_with_Xpm_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xpm_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xpm_library" >&5 $as_echo "$smr_cv_with_Xpm_library" >&6; } case x"$smr_cv_with_Xpm_library" in xyes | xmaybe) Xpm_LIBS="-lXpm" with_Xpm=$smr_cv_with_Xpm_library ;; xno) Xpm_LIBS= with_Xpm=no ;; *) if test -f "$smr_cv_with_Xpm_library"; then Xpm_LIBS=$smr_cv_with_Xpm_library elif test -d "$smr_cv_with_Xpm_library"; then Xpm_LIBS="-L$smr_cv_with_Xpm_library -lXpm" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Xpm=yes ;; esac if test ! x"$with_Xpm" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Xpm-includes was given. if test "${with_Xpm_includes+set}" = set; then : withval=$with_Xpm_includes; smr_cv_with_Xpm_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Xpm header files" >&5 $as_echo_n "checking where to find the Xpm header files... " >&6; } if test "${smr_cv_with_Xpm_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xpm_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xpm_includes" >&5 $as_echo "$smr_cv_with_Xpm_includes" >&6; } if test ! x"$smr_cv_with_Xpm_includes" = x; then if test -d "$smr_cv_with_Xpm_includes"; then Xpm_CFLAGS="-I$smr_cv_with_Xpm_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Xpm_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Xpm_CFLAGS $X_CFLAGS" for ac_header in X11/xpm.h do : ac_fn_c_check_header_mongrel "$LINENO" "X11/xpm.h" "ac_cv_header_X11_xpm_h" "$ac_includes_default" if test "x$ac_cv_header_X11_xpm_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_X11_XPM_H 1 _ACEOF smr_have_Xpm_header=yes else smr_have_Xpm_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Xpm_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpmCreatePixmapFromData in -lXpm" >&5 $as_echo_n "checking for XpmCreatePixmapFromData in -lXpm... " >&6; } if test "${ac_cv_lib_Xpm_XpmCreatePixmapFromData+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXpm $Xpm_CFLAGS $X_CFLAGS $Xpm_LIBS $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XpmCreatePixmapFromData (); int main () { return XpmCreatePixmapFromData (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xpm_XpmCreatePixmapFromData=yes else ac_cv_lib_Xpm_XpmCreatePixmapFromData=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&5 $as_echo "$ac_cv_lib_Xpm_XpmCreatePixmapFromData" >&6; } if test "x$ac_cv_lib_Xpm_XpmCreatePixmapFromData" = x""yes; then : smr_have_Xpm_library=yes else smr_have_Xpm_library=no fi fi if test x"$smr_have_Xpm_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Xpm library" >&5 $as_echo "using Xpm library" >&6; } else Xpm_LIBS= Xpm_CFLAGS= if test x"$with_Xpm" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Xpm library" >&5 $as_echo "not using Xpm library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Xpm library not found!" >&5 $as_echo "$as_me: WARNING: requested Xpm library not found!" >&2;} fi fi fi fi if test -z "$no_x"; then # Check whether --with-Xext-library was given. if test "${with_Xext_library+set}" = set; then : withval=$with_Xext_library; smr_cv_with_Xext_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Xext library" >&5 $as_echo_n "checking whether to use Xext library... " >&6; } if test "${smr_cv_with_Xext_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xext_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xext_library" >&5 $as_echo "$smr_cv_with_Xext_library" >&6; } case x"$smr_cv_with_Xext_library" in xyes | xmaybe) Xext_LIBS="-lXext" with_Xext=$smr_cv_with_Xext_library ;; xno) Xext_LIBS= with_Xext=no ;; *) if test -f "$smr_cv_with_Xext_library"; then Xext_LIBS=$smr_cv_with_Xext_library elif test -d "$smr_cv_with_Xext_library"; then Xext_LIBS="-L$smr_cv_with_Xext_library -lXext" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Xext=yes ;; esac if test ! x"$with_Xext" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Xext-includes was given. if test "${with_Xext_includes+set}" = set; then : withval=$with_Xext_includes; smr_cv_with_Xext_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Xext header files" >&5 $as_echo_n "checking where to find the Xext header files... " >&6; } if test "${smr_cv_with_Xext_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xext_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xext_includes" >&5 $as_echo "$smr_cv_with_Xext_includes" >&6; } if test ! x"$smr_cv_with_Xext_includes" = x; then if test -d "$smr_cv_with_Xext_includes"; then Xext_CFLAGS="-I$smr_cv_with_Xext_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Xext_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Xext_CFLAGS $X_CFLAGS" for ac_header in X11/Xlib.h do : ac_fn_c_check_header_mongrel "$LINENO" "X11/Xlib.h" "ac_cv_header_X11_Xlib_h" "$ac_includes_default" if test "x$ac_cv_header_X11_Xlib_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_X11_XLIB_H 1 _ACEOF smr_have_Xext_header=yes else smr_have_Xext_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Xext_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XextAddDisplay in -lXext" >&5 $as_echo_n "checking for XextAddDisplay in -lXext... " >&6; } if test "${ac_cv_lib_Xext_XextAddDisplay+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXext $Xext_CFLAGS $X_CFLAGS $Xext_LIBS $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XextAddDisplay (); int main () { return XextAddDisplay (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xext_XextAddDisplay=yes else ac_cv_lib_Xext_XextAddDisplay=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xext_XextAddDisplay" >&5 $as_echo "$ac_cv_lib_Xext_XextAddDisplay" >&6; } if test "x$ac_cv_lib_Xext_XextAddDisplay" = x""yes; then : smr_have_Xext_library=yes else smr_have_Xext_library=no fi fi if test x"$smr_have_Xext_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Xext library" >&5 $as_echo "using Xext library" >&6; } else Xext_LIBS= Xext_CFLAGS= if test x"$with_Xext" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Xext library" >&5 $as_echo "not using Xext library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Xext library not found!" >&5 $as_echo "$as_me: WARNING: requested Xext library not found!" >&2;} fi fi fi # Check whether --with-Xp-library was given. if test "${with_Xp_library+set}" = set; then : withval=$with_Xp_library; smr_cv_with_Xp_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Xp library" >&5 $as_echo_n "checking whether to use Xp library... " >&6; } if test "${smr_cv_with_Xp_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xp_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xp_library" >&5 $as_echo "$smr_cv_with_Xp_library" >&6; } case x"$smr_cv_with_Xp_library" in xyes | xmaybe) Xp_LIBS="-lXp" with_Xp=$smr_cv_with_Xp_library ;; xno) Xp_LIBS= with_Xp=no ;; *) if test -f "$smr_cv_with_Xp_library"; then Xp_LIBS=$smr_cv_with_Xp_library elif test -d "$smr_cv_with_Xp_library"; then Xp_LIBS="-L$smr_cv_with_Xp_library -lXp" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Xp=yes ;; esac if test ! x"$with_Xp" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Xp-includes was given. if test "${with_Xp_includes+set}" = set; then : withval=$with_Xp_includes; smr_cv_with_Xp_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Xp header files" >&5 $as_echo_n "checking where to find the Xp header files... " >&6; } if test "${smr_cv_with_Xp_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xp_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xp_includes" >&5 $as_echo "$smr_cv_with_Xp_includes" >&6; } if test ! x"$smr_cv_with_Xp_includes" = x; then if test -d "$smr_cv_with_Xp_includes"; then Xp_CFLAGS="-I$smr_cv_with_Xp_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Xp_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Xp_CFLAGS $X_CFLAGS" for ac_header in X11/extensions/Print.h do : ac_fn_c_check_header_mongrel "$LINENO" "X11/extensions/Print.h" "ac_cv_header_X11_extensions_Print_h" "$ac_includes_default" if test "x$ac_cv_header_X11_extensions_Print_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_X11_EXTENSIONS_PRINT_H 1 _ACEOF smr_have_Xp_header=yes else smr_have_Xp_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Xp_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XpStartPage in -lXp" >&5 $as_echo_n "checking for XpStartPage in -lXp... " >&6; } if test "${ac_cv_lib_Xp_XpStartPage+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXp $Xp_CFLAGS $X_CFLAGS $Xp_LIBS $X_LIBS $X_PRE_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XpStartPage (); int main () { return XpStartPage (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xp_XpStartPage=yes else ac_cv_lib_Xp_XpStartPage=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xp_XpStartPage" >&5 $as_echo "$ac_cv_lib_Xp_XpStartPage" >&6; } if test "x$ac_cv_lib_Xp_XpStartPage" = x""yes; then : smr_have_Xp_library=yes else smr_have_Xp_library=no fi fi if test x"$smr_have_Xp_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Xp library" >&5 $as_echo "using Xp library" >&6; } else Xp_LIBS= Xp_CFLAGS= if test x"$with_Xp" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Xp library" >&5 $as_echo "not using Xp library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Xp library not found!" >&5 $as_echo "$as_me: WARNING: requested Xp library not found!" >&2;} fi fi fi # Check whether --with-Xt-library was given. if test "${with_Xt_library+set}" = set; then : withval=$with_Xt_library; smr_cv_with_Xt_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Xt library" >&5 $as_echo_n "checking whether to use Xt library... " >&6; } if test "${smr_cv_with_Xt_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xt_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xt_library" >&5 $as_echo "$smr_cv_with_Xt_library" >&6; } case x"$smr_cv_with_Xt_library" in xyes | xmaybe) Xt_LIBS="-lXt" with_Xt=$smr_cv_with_Xt_library ;; xno) Xt_LIBS= with_Xt=no ;; *) if test -f "$smr_cv_with_Xt_library"; then Xt_LIBS=$smr_cv_with_Xt_library elif test -d "$smr_cv_with_Xt_library"; then Xt_LIBS="-L$smr_cv_with_Xt_library -lXt" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Xt=yes ;; esac if test ! x"$with_Xt" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Xt-includes was given. if test "${with_Xt_includes+set}" = set; then : withval=$with_Xt_includes; smr_cv_with_Xt_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Xt header files" >&5 $as_echo_n "checking where to find the Xt header files... " >&6; } if test "${smr_cv_with_Xt_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xt_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xt_includes" >&5 $as_echo "$smr_cv_with_Xt_includes" >&6; } if test ! x"$smr_cv_with_Xt_includes" = x; then if test -d "$smr_cv_with_Xt_includes"; then Xt_CFLAGS="-I$smr_cv_with_Xt_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Xt_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Xt_CFLAGS $X_CFLAGS" for ac_header in X11/Intrinsic.h do : ac_fn_c_check_header_mongrel "$LINENO" "X11/Intrinsic.h" "ac_cv_header_X11_Intrinsic_h" "$ac_includes_default" if test "x$ac_cv_header_X11_Intrinsic_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_X11_INTRINSIC_H 1 _ACEOF smr_have_Xt_header=yes else smr_have_Xt_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Xt_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtAppInitialize in -lXt" >&5 $as_echo_n "checking for XtAppInitialize in -lXt... " >&6; } if test "${ac_cv_lib_Xt_XtAppInitialize+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt $Xt_CFLAGS $X_CFLAGS $Xt_LIBS $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtAppInitialize (); int main () { return XtAppInitialize (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtAppInitialize=yes else ac_cv_lib_Xt_XtAppInitialize=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtAppInitialize" >&5 $as_echo "$ac_cv_lib_Xt_XtAppInitialize" >&6; } if test "x$ac_cv_lib_Xt_XtAppInitialize" = x""yes; then : smr_have_Xt_library=yes else smr_have_Xt_library=no fi fi if test x"$smr_have_Xt_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Xt library" >&5 $as_echo "using Xt library" >&6; } else Xt_LIBS= Xt_CFLAGS= if test x"$with_Xt" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Xt library" >&5 $as_echo "not using Xt library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Xt library not found!" >&5 $as_echo "$as_me: WARNING: requested Xt library not found!" >&2;} fi fi fi # Check whether --with-Xm-library was given. if test "${with_Xm_library+set}" = set; then : withval=$with_Xm_library; smr_cv_with_Xm_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Xm library" >&5 $as_echo_n "checking whether to use Xm library... " >&6; } if test "${smr_cv_with_Xm_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xm_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xm_library" >&5 $as_echo "$smr_cv_with_Xm_library" >&6; } case x"$smr_cv_with_Xm_library" in xyes | xmaybe) Xm_LIBS="-lXm" with_Xm=$smr_cv_with_Xm_library ;; xno) Xm_LIBS= with_Xm=no ;; *) if test -f "$smr_cv_with_Xm_library"; then Xm_LIBS=$smr_cv_with_Xm_library elif test -d "$smr_cv_with_Xm_library"; then Xm_LIBS="-L$smr_cv_with_Xm_library -lXm" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Xm=yes ;; esac if test ! x"$with_Xm" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Xm-includes was given. if test "${with_Xm_includes+set}" = set; then : withval=$with_Xm_includes; smr_cv_with_Xm_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Xm header files" >&5 $as_echo_n "checking where to find the Xm header files... " >&6; } if test "${smr_cv_with_Xm_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Xm_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Xm_includes" >&5 $as_echo "$smr_cv_with_Xm_includes" >&6; } if test ! x"$smr_cv_with_Xm_includes" = x; then if test -d "$smr_cv_with_Xm_includes"; then Xm_CFLAGS="-I$smr_cv_with_Xm_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Xm_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Xm_CFLAGS $X_CFLAGS" for ac_header in Xm/XmAll.h do : ac_fn_c_check_header_mongrel "$LINENO" "Xm/XmAll.h" "ac_cv_header_Xm_XmAll_h" "$ac_includes_default" if test "x$ac_cv_header_Xm_XmAll_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_XM_XMALL_H 1 _ACEOF smr_have_Xm_header=yes else smr_have_Xm_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Xm_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XmCreateForm in -lXm" >&5 $as_echo_n "checking for XmCreateForm in -lXm... " >&6; } if test "${ac_cv_lib_Xm_XmCreateForm+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXm $Xm_CFLAGS $X_CFLAGS $Xm_LIBS $Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XmCreateForm (); int main () { return XmCreateForm (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xm_XmCreateForm=yes else ac_cv_lib_Xm_XmCreateForm=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xm_XmCreateForm" >&5 $as_echo "$ac_cv_lib_Xm_XmCreateForm" >&6; } if test "x$ac_cv_lib_Xm_XmCreateForm" = x""yes; then : smr_have_Xm_library=yes else smr_have_Xm_library=no fi fi if test x"$smr_have_Xm_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Xm library" >&5 $as_echo "using Xm library" >&6; } else Xm_LIBS= Xm_CFLAGS= if test x"$with_Xm" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Xm library" >&5 $as_echo "not using Xm library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Xm library not found!" >&5 $as_echo "$as_me: WARNING: requested Xm library not found!" >&2;} fi fi fi # Check whether --with-Sgm-library was given. if test "${with_Sgm_library+set}" = set; then : withval=$with_Sgm_library; smr_cv_with_Sgm_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use Sgm library" >&5 $as_echo_n "checking whether to use Sgm library... " >&6; } if test "${smr_cv_with_Sgm_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Sgm_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Sgm_library" >&5 $as_echo "$smr_cv_with_Sgm_library" >&6; } case x"$smr_cv_with_Sgm_library" in xyes | xmaybe) Sgm_LIBS="-lSgm" with_Sgm=$smr_cv_with_Sgm_library ;; xno) Sgm_LIBS= with_Sgm=no ;; *) if test -f "$smr_cv_with_Sgm_library"; then Sgm_LIBS=$smr_cv_with_Sgm_library elif test -d "$smr_cv_with_Sgm_library"; then Sgm_LIBS="-L$smr_cv_with_Sgm_library -lSgm" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_Sgm=yes ;; esac if test ! x"$with_Sgm" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-Sgm-includes was given. if test "${with_Sgm_includes+set}" = set; then : withval=$with_Sgm_includes; smr_cv_with_Sgm_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the Sgm header files" >&5 $as_echo_n "checking where to find the Sgm header files... " >&6; } if test "${smr_cv_with_Sgm_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_Sgm_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_Sgm_includes" >&5 $as_echo "$smr_cv_with_Sgm_includes" >&6; } if test ! x"$smr_cv_with_Sgm_includes" = x; then if test -d "$smr_cv_with_Sgm_includes"; then Sgm_CFLAGS="-I$smr_cv_with_Sgm_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else Sgm_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $Sgm_CFLAGS $X_CFLAGS" for ac_header in Sgm/HPanedW.h do : ac_fn_c_check_header_mongrel "$LINENO" "Sgm/HPanedW.h" "ac_cv_header_Sgm_HPanedW_h" "$ac_includes_default" if test "x$ac_cv_header_Sgm_HPanedW_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_SGM_HPANEDW_H 1 _ACEOF smr_have_Sgm_header=yes else smr_have_Sgm_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_Sgm_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SgCreateHorzPanedWindow in -lSgm" >&5 $as_echo_n "checking for SgCreateHorzPanedWindow in -lSgm... " >&6; } if test "${ac_cv_lib_Sgm_SgCreateHorzPanedWindow+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lSgm $Sgm_CFLAGS $X_CFLAGS $Sgm_LIBS $Xm_LIBS $Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char SgCreateHorzPanedWindow (); int main () { return SgCreateHorzPanedWindow (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Sgm_SgCreateHorzPanedWindow=yes else ac_cv_lib_Sgm_SgCreateHorzPanedWindow=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Sgm_SgCreateHorzPanedWindow" >&5 $as_echo "$ac_cv_lib_Sgm_SgCreateHorzPanedWindow" >&6; } if test "x$ac_cv_lib_Sgm_SgCreateHorzPanedWindow" = x""yes; then : smr_have_Sgm_library=yes else smr_have_Sgm_library=no fi fi if test x"$smr_have_Sgm_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using Sgm library" >&5 $as_echo "using Sgm library" >&6; } else Sgm_LIBS= Sgm_CFLAGS= if test x"$with_Sgm" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using Sgm library" >&5 $as_echo "not using Sgm library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested Sgm library not found!" >&5 $as_echo "$as_me: WARNING: requested Sgm library not found!" >&2;} fi fi fi if test "x$smr_have_Xt_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for XtAppSetExitFlag in -lXt" >&5 $as_echo_n "checking for XtAppSetExitFlag in -lXt... " >&6; } if test "${ac_cv_lib_Xt_XtAppSetExitFlag+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lXt $Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char XtAppSetExitFlag (); int main () { return XtAppSetExitFlag (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_Xt_XtAppSetExitFlag=yes else ac_cv_lib_Xt_XtAppSetExitFlag=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_Xt_XtAppSetExitFlag" >&5 $as_echo "$ac_cv_lib_Xt_XtAppSetExitFlag" >&6; } if test "x$ac_cv_lib_Xt_XtAppSetExitFlag" = x""yes; then : $as_echo "#define HAVE_XTAPPSETEXITFLAG 1" >>confdefs.h fi fi fi #dnl ##### Check for t1lib. #smr_CHECK_LIB(t1, t1, [Type 1 font rasterizer], # T1_InitLib, t1lib.h, # -lm, $X_CFLAGS) # t1lib has some potential security holes, and hasn't been updated in # years -- if you really want to use it, uncomment the preceding lines, # and comment out the next two lines t1_LIBS="" t1_CFLAGS="" # Check whether --with-freetype2-library was given. if test "${with_freetype2_library+set}" = set; then : withval=$with_freetype2_library; smr_cv_with_freetype2_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use freetype2 library" >&5 $as_echo_n "checking whether to use freetype2 library... " >&6; } if test "${smr_cv_with_freetype2_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_freetype2_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_freetype2_library" >&5 $as_echo "$smr_cv_with_freetype2_library" >&6; } case x"$smr_cv_with_freetype2_library" in xyes | xmaybe) freetype2_LIBS="-lfreetype" with_freetype2=$smr_cv_with_freetype2_library ;; xno) freetype2_LIBS= with_freetype2=no ;; *) if test -f "$smr_cv_with_freetype2_library"; then freetype2_LIBS=$smr_cv_with_freetype2_library elif test -d "$smr_cv_with_freetype2_library"; then freetype2_LIBS="-L$smr_cv_with_freetype2_library -lfreetype" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_freetype2=yes ;; esac if test ! x"$with_freetype2" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-freetype2-includes was given. if test "${with_freetype2_includes+set}" = set; then : withval=$with_freetype2_includes; smr_cv_with_freetype2_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the freetype2 header files" >&5 $as_echo_n "checking where to find the freetype2 header files... " >&6; } if test "${smr_cv_with_freetype2_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_freetype2_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_freetype2_includes" >&5 $as_echo "$smr_cv_with_freetype2_includes" >&6; } if test ! x"$smr_cv_with_freetype2_includes" = x; then if test -d "$smr_cv_with_freetype2_includes"; then freetype2_CFLAGS="-I$smr_cv_with_freetype2_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else freetype2_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $freetype2_CFLAGS " for ac_header in ft2build.h do : ac_fn_c_check_header_mongrel "$LINENO" "ft2build.h" "ac_cv_header_ft2build_h" "$ac_includes_default" if test "x$ac_cv_header_ft2build_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_FT2BUILD_H 1 _ACEOF smr_have_freetype2_header=yes else smr_have_freetype2_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_freetype2_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for FT_Get_Name_Index in -lfreetype" >&5 $as_echo_n "checking for FT_Get_Name_Index in -lfreetype... " >&6; } if test "${ac_cv_lib_freetype_FT_Get_Name_Index+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lfreetype $freetype2_CFLAGS $freetype2_LIBS -lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char FT_Get_Name_Index (); int main () { return FT_Get_Name_Index (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_freetype_FT_Get_Name_Index=yes else ac_cv_lib_freetype_FT_Get_Name_Index=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_freetype_FT_Get_Name_Index" >&5 $as_echo "$ac_cv_lib_freetype_FT_Get_Name_Index" >&6; } if test "x$ac_cv_lib_freetype_FT_Get_Name_Index" = x""yes; then : smr_have_freetype2_library=yes else smr_have_freetype2_library=no fi fi if test x"$smr_have_freetype2_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using freetype2 library" >&5 $as_echo "using freetype2 library" >&6; } else freetype2_LIBS= freetype2_CFLAGS= if test x"$with_freetype2" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using freetype2 library" >&5 $as_echo "not using freetype2 library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested freetype2 library not found!" >&5 $as_echo "$as_me: WARNING: requested freetype2 library not found!" >&2;} fi fi fi if test "x$smr_have_freetype2_library" = xyes; then $as_echo "#define HAVE_FREETYPE_FREETYPE_H 1" >>confdefs.h $as_echo "#define HAVE_SPLASH 1" >>confdefs.h fi # Check whether --with-libpaper-library was given. if test "${with_libpaper_library+set}" = set; then : withval=$with_libpaper_library; smr_cv_with_libpaper_library=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use libpaper library" >&5 $as_echo_n "checking whether to use libpaper library... " >&6; } if test "${smr_cv_with_libpaper_library+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_libpaper_library=maybe fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_libpaper_library" >&5 $as_echo "$smr_cv_with_libpaper_library" >&6; } case x"$smr_cv_with_libpaper_library" in xyes | xmaybe) libpaper_LIBS="-lpaper" with_libpaper=$smr_cv_with_libpaper_library ;; xno) libpaper_LIBS= with_libpaper=no ;; *) if test -f "$smr_cv_with_libpaper_library"; then libpaper_LIBS=$smr_cv_with_libpaper_library elif test -d "$smr_cv_with_libpaper_library"; then libpaper_LIBS="-L$smr_cv_with_libpaper_library -lpaper" else as_fn_error "argument must be boolean, file, or directory" "$LINENO" 5 fi with_libpaper=yes ;; esac if test ! x"$with_libpaper" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. # Check whether --with-libpaper-includes was given. if test "${with_libpaper_includes+set}" = set; then : withval=$with_libpaper_includes; smr_cv_with_libpaper_includes=$withval fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking where to find the libpaper header files" >&5 $as_echo_n "checking where to find the libpaper header files... " >&6; } if test "${smr_cv_with_libpaper_includes+set}" = set; then : $as_echo_n "(cached) " >&6 else smr_cv_with_libpaper_includes= fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $smr_cv_with_libpaper_includes" >&5 $as_echo "$smr_cv_with_libpaper_includes" >&6; } if test ! x"$smr_cv_with_libpaper_includes" = x; then if test -d "$smr_cv_with_libpaper_includes"; then libpaper_CFLAGS="-I$smr_cv_with_libpaper_includes" else as_fn_error "argument must be a directory" "$LINENO" 5 fi else libpaper_CFLAGS= fi smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS $libpaper_CFLAGS " for ac_header in paper.h do : ac_fn_c_check_header_mongrel "$LINENO" "paper.h" "ac_cv_header_paper_h" "$ac_includes_default" if test "x$ac_cv_header_paper_h" = x""yes; then : cat >>confdefs.h <<_ACEOF #define HAVE_PAPER_H 1 _ACEOF smr_have_libpaper_header=yes else smr_have_libpaper_header=no fi done if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi # We need only look for the library if the header has been found # (or no header is needed). if test $smr_have_libpaper_header != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for paperinit in -lpaper" >&5 $as_echo_n "checking for paperinit in -lpaper... " >&6; } if test "${ac_cv_lib_paper_paperinit+set}" = set; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpaper $libpaper_CFLAGS $libpaper_LIBS $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char paperinit (); int main () { return paperinit (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_paper_paperinit=yes else ac_cv_lib_paper_paperinit=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_paper_paperinit" >&5 $as_echo "$ac_cv_lib_paper_paperinit" >&6; } if test "x$ac_cv_lib_paper_paperinit" = x""yes; then : smr_have_libpaper_library=yes else smr_have_libpaper_library=no fi fi if test x"$smr_have_libpaper_library" = xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: using libpaper library" >&5 $as_echo "using libpaper library" >&6; } else libpaper_LIBS= libpaper_CFLAGS= if test x"$with_libpaper" = xmaybe; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: not using libpaper library" >&5 $as_echo "not using libpaper library" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: requested libpaper library not found!" >&5 $as_echo "$as_me: WARNING: requested libpaper library not found!" >&2;} fi fi fi if test -n "$no_x" -o "x$smr_have_Xm_library" != xyes -o "x$smr_have_freetype2_library" != xyes; then X="#" XPDF_TARGET="all-no-x" else X="" XPDF_TARGET="all" fi ac_config_files="$ac_config_files Makefile goo/Makefile fofi/Makefile splash/Makefile xpdf/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then test "x$cache_file" != "x/dev/null" && { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} cat confcache >$cache_file else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : ${CONFIG_STATUS=./config.status} ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error ERROR [LINENO LOG_FD] # --------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with status $?, using 1 if that was 0. as_fn_error () { as_status=$?; test $as_status -eq 0 && as_status=1 if test "$3"; then as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 fi $as_echo "$as_me: error: $1" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by $as_me, which was generated by GNU Autoconf 2.65. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ config.status configured by $0, generated by GNU Autoconf 2.65, with options \\"\$ac_cs_config\\" Copyright (C) 2009 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "aconf.h") CONFIG_HEADERS="$CONFIG_HEADERS aconf.h" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "goo/Makefile") CONFIG_FILES="$CONFIG_FILES goo/Makefile" ;; "fofi/Makefile") CONFIG_FILES="$CONFIG_FILES fofi/Makefile" ;; "splash/Makefile") CONFIG_FILES="$CONFIG_FILES splash/Makefile" ;; "xpdf/Makefile") CONFIG_FILES="$CONFIG_FILES xpdf/Makefile" ;; *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= trap 'exit_status=$? { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ || as_fn_error "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove $(srcdir), # ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=/{ s/:*\$(srcdir):*/:/ s/:*\${srcdir}:*/:/ s/:*@srcdir@:*/:/ s/^\([^=]*=[ ]*\):*/\1/ s/:*$// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_t=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_t"; then break elif $ac_last_try; then as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$tmp/stdin" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ || as_fn_error "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined." >&2;} rm -f "$tmp/stdin" case $ac_file in -) cat "$tmp/out" && rm -f "$tmp/out";; *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; esac \ || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" } >"$tmp/config.h" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$tmp/config.h" "$ac_file" \ || as_fn_error "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error "could not create -" "$LINENO" 5 fi ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit $? fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if test -n "$no_x" -o "x$smr_have_Xm_library" != xyes -o "x$smr_have_freetype2_library" != xyes; then if test -n "$no_x"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Couldn't find X" >&5 $as_echo "$as_me: WARNING: Couldn't find X" >&2;}; fi if test "x$smr_have_Xm_library" != xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Couldn't find Motif" >&5 $as_echo "$as_me: WARNING: Couldn't find Motif" >&2;}; fi if test "x$smr_have_freetype2_library" != xyes; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Couldn't find FreeType" >&5 $as_echo "$as_me: WARNING: Couldn't find FreeType" >&2;}; fi { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: -- You will be able to compile pdftops, pdftotext, pdfinfo, pdffonts, pdfdetach, and pdfimages, but not xpdf or pdftoppm" >&5 $as_echo "$as_me: WARNING: -- You will be able to compile pdftops, pdftotext, pdfinfo, pdffonts, pdfdetach, and pdfimages, but not xpdf or pdftoppm" >&2;} fi xpdf-3.03/configure.in0000644000076400007640000002630111622305345014226 0ustar dereknderekndnl Process this file with autoconf to produce a configure script. dnl Copyright 1998-2005 Glyph & Cog, LLC AC_PREREQ(2.57) AC_INIT(xpdf/Gfx.cc) AC_CONFIG_HEADER(aconf.h) dnl ##### Optional features. AC_ARG_ENABLE(a4-paper, [ --enable-a4-paper use A4 paper size instead of Letter for PostScript output], AC_DEFINE(A4_PAPER)) AC_ARG_ENABLE(no-text-select, [ --enable-no-text-select do not allow text selection], AC_DEFINE(NO_TEXT_SELECT)) AC_ARG_ENABLE(opi, [ --enable-opi include support for OPI comments], AC_DEFINE(OPI_SUPPORT)) AC_ARG_ENABLE(multithreaded, [ --enable-multithreaded include support for multithreading], AC_DEFINE(MULTITHREADED)) AC_ARG_ENABLE(exceptions, [ --enable-exceptions use C++ exceptions], AC_DEFINE(USE_EXCEPTIONS)) AC_ARG_ENABLE(wordlist, [ --enable-wordlist include support for building word lists], AC_DEFINE(TEXTOUT_WORD_LIST)) AC_ARG_ENABLE(fixedpoint, [ --enable-fixedpoint use fixed point (instead of floating point) arithmetic], AC_DEFINE(USE_FIXEDPOINT)) AC_ARG_ENABLE(cmyk, [ --enable-cmyk include support for CMYK rasterization], AC_DEFINE(SPLASH_CMYK)) AC_ARG_WITH(appdef-dir, [ --with-appdef-dir set app-defaults directory], AC_DEFINE_UNQUOTED(APPDEFDIR, "$with_appdef_dir")) dnl ##### Path to xpdfrc. dnl This ugly kludge to get the sysconfdir path is needed because dnl autoconf doesn't actually set the prefix variable until later. if test "$sysconfdir" = '${prefix}/etc'; then if test "x$prefix" = xNONE; then system_xpdfrc="$ac_default_prefix/etc/xpdfrc" else system_xpdfrc="$prefix/etc/xpdfrc" fi else system_xpdfrc="$sysconfdir/xpdfrc" fi AC_DEFINE_UNQUOTED(SYSTEM_XPDFRC, "$system_xpdfrc") dnl ##### Checks for programs. AC_PROG_CC AC_ISC_POSIX AC_PROG_CC_STDC #if test -z "$CXX" -a "$CC" = "gcc"; then # CXX="gcc" #fi AC_PROG_CXX AC_PROG_INSTALL AC_PROG_RANLIB dnl ##### Default values for Unix. EXE="" LIBPREFIX="lib" AR="ar rc" UP_DIR="" dnl ##### Check for OS/2. AC_CACHE_CHECK([for OS/2 (with EMX)], xpdf_cv_sys_os2, [AC_TRY_COMPILE([], [__EMX__], xpdf_cv_sys_os2=yes, xpdf_cv_sys_os2=no)]) if test "$xpdf_cv_sys_os2" = yes; then EXE=".exe" LIBPREFIX="" AR="ar -rc" fi dnl ##### Check for DOS (with DJGPP). AC_CACHE_CHECK([for DOS (with DJGPP)], xpdf_cv_sys_dos, [AC_TRY_COMPILE([], [__DJGPP__], xpdf_cv_sys_dos=yes, xpdf_cv_sys_dos=no)]) if test "$xpdf_cv_sys_dos" = yes; then EXE=".exe" LIBPREFIX="lib" AR="ar -rc" UP_DIR="../" fi dnl ##### Do substitutions. AC_SUBST(EXE) AC_SUBST(LIBPREFIX) AC_SUBST(AR) AC_SUBST(UP_DIR) dnl ##### Checks for header files. AC_PATH_XTRA AC_HEADER_DIRENT dnl ##### Switch over to C++. This will make the checks below a little dnl ##### bit stricter (requiring function prototypes in include files). dnl ##### (99% of xpdf is written in C++.) AC_LANG_CPLUSPLUS dnl ##### Check for extra libraries needed by X. (LynxOS needs this.) AC_CHECK_FUNC(gethostbyname) if test $ac_cv_func_gethostbyname = no; then AC_CHECK_LIB(bsd, gethostbyname, X_EXTRA_LIBS="$X_EXTRA_LIBS -lbsd") fi dnl ##### Look for header that defines select() and fd_set. AC_MSG_CHECKING([select() and fd_set in sys/select.h and sys/bsdtypes.h]) AC_TRY_COMPILE([#include #include #include #include ], [fd_set fds; select(0, NULL, NULL, NULL, NULL);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_MSG_RESULT([not needed]) else AC_TRY_COMPILE([#include #include #include #include #include ], [fd_set fds; select(0, NULL, NULL, NULL, NULL);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_DEFINE(HAVE_SYS_SELECT_H) AC_MSG_RESULT([need sys/select.h]) else AC_TRY_COMPILE([#include #include #include #include #include ], [fd_set fds; select(0, NULL, NULL, NULL, NULL);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_DEFINE(HAVE_SYS_BSDTYPES_H) AC_MSG_RESULT([need sys/bsdtypes.h]) else AC_MSG_RESULT([problem]) fi fi fi dnl ##### Look for header that defines FD_ZERO. AC_MSG_CHECKING([FD_ZERO and strings.h or bstring.h]) AC_TRY_COMPILE([#include #include #ifdef HAVE_SYS_SELECT_H #include #endif], [fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_MSG_RESULT([not needed]) else AC_TRY_COMPILE([#include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif], [fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_DEFINE(HAVE_STRINGS_H) AC_MSG_RESULT([need strings.h]) else AC_TRY_COMPILE([#include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif], [fd_set fds; FD_ZERO(&fds);], xpdf_ok=yes, xpdf_ok=no) if test $xpdf_ok = yes; then AC_DEFINE(HAVE_BSTRING_H) AC_MSG_RESULT([need bstring.h]) else AC_MSG_RESULT([problem]) fi fi fi dnl ##### Look for rewinddir. AC_CHECK_FUNCS(rewinddir) if test $ac_cv_func_rewinddir = no; then AC_CHECK_LIB(cposix, rewinddir) fi dnl ##### Checks for library functions. AC_CHECK_FUNCS(popen) dnl # This should use 'AC_CHECK_FUNCS(mkstemp)' but that fails if dnl # the mkstemp exists in the library but isn't declared in the dnl # include file (e.g., in cygwin 1.1.2). AC_CACHE_CHECK([for mkstemp], xpdf_cv_func_mkstemp, [AC_TRY_LINK([#include #include ], [mkstemp("foo");], xpdf_cv_func_mkstemp=yes, xpdf_cv_func_mkstemp=no)]) if test "$xpdf_cv_func_mkstemp" = yes; then AC_DEFINE(HAVE_MKSTEMP) fi dnl # Check for mkstemps, just like mkstemp. AC_CACHE_CHECK([for mkstemps], xpdf_cv_func_mkstemps, [AC_TRY_LINK([#include #include ], [mkstemps("foo", 0);], xpdf_cv_func_mkstemps=yes, xpdf_cv_func_mkstemps=no)]) if test "$xpdf_cv_func_mkstemps" = yes; then AC_DEFINE(HAVE_MKSTEMPS) fi dnl ##### Check select argument type: on HP-UX before version 10, select dnl ##### takes (int *) instead of (fd_set *). AC_CACHE_CHECK([whether select takes fd_set arguments], xpdf_cv_func_select_arg, [AC_TRY_COMPILE([#include #include #include #ifdef HAVE_SYS_SELECT_H #include #endif], [fd_set fds; select(1, &fds, &fds, &fds, 0);], xpdf_cv_func_select_arg=yes, xpdf_cv_func_select_arg=no)]) if test "$xpdf_cv_func_select_arg" != yes; then AC_DEFINE(SELECT_TAKES_INT) fi dnl ##### Check for std::sort. AC_CACHE_CHECK([for std::sort], xpdf_cv_func_std_sort, [AC_COMPILE_IFELSE( AC_LANG_PROGRAM([[#include struct functor { bool operator()(const int &i0, const int &i1) { return i0 < i1; } };]], [[int a[[100]]; std::sort(a, a+100, functor());]]), xpdf_cv_func_std_sort=yes, xpdf_cv_func_std_sort=no)]) if test "$xpdf_cv_func_std_sort" = yes; then AC_DEFINE(HAVE_STD_SORT) fi dnl ##### Back to C for the library tests. AC_LANG_C dnl ##### Check for fseeko/ftello or fseek64/ftell64 dnl The LARGEFILE and FSEEKO macros have to be called in C, not C++, mode. AC_SYS_LARGEFILE AC_FUNC_FSEEKO AC_CHECK_FUNCS(fseek64, xpdf_cv_func_fseek64=yes, xpdf_cv_func_fseek64=no) AC_CHECK_FUNCS(ftell64, xpdf_cv_func_ftell64=yes, xpdf_cv_func_ftell64=no) if test "$xpdf_cv_func_fseek64" = yes -a "$xpdf_cv_func_ftell64" = yes; then AC_DEFINE(HAVE_FSEEK64) fi dnl ##### Check for libXpm. if test -z "$no_x"; then smr_CHECK_LIB(Xpm, Xpm, [pixmap library - used only for icon], XpmCreatePixmapFromData, X11/xpm.h, $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS) AC_SUBST(Xpm_LIBS) AC_SUBST(Xpm_CFLAGS) fi dnl ##### Check for Motif (libXm). if test -z "$no_x"; then dnl # XextAddDisplay isn't defined in any header file, so we provide a dnl # bogus prototype (so the compiler doesn't complain) and a bogus dnl # header file (so the smr macro doesn't break). smr_CHECK_LIB(Xext, Xext, [Motif library], XextAddDisplay, X11/Xlib.h, $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS, [int XextAddDisplay();]) AC_SUBST(Xext_LIBS) AC_SUBST(Xext_CFLAGS) smr_CHECK_LIB(Xp, Xp, [Motif library], XpStartPage, X11/extensions/Print.h, $X_LIBS $X_PRE_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS) AC_SUBST(Xp_LIBS) AC_SUBST(Xp_CFLAGS) smr_CHECK_LIB(Xt, Xt, [Motif library], XtAppInitialize, X11/Intrinsic.h, $X_LIBS $X_PRE_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS) AC_SUBST(Xt_LIBS) AC_SUBST(Xt_CFLAGS) smr_CHECK_LIB(Xm, Xm, [Motif library], XmCreateForm, Xm/XmAll.h, $Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS) AC_SUBST(Xm_LIBS) AC_SUBST(Xm_CFLAGS) smr_CHECK_LIB(Sgm, Sgm, [SGI Motif library], SgCreateHorzPanedWindow, Sgm/HPanedW.h, $Xm_LIBS $Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11, $X_CFLAGS) AC_SUBST(Sgm_LIBS) AC_SUBST(Sgm_CFLAGS) dnl # check for XtAppSetExitFlag, which didn't exist prior to X11R6 (?) if test "x$smr_have_Xt_library" = xyes; then AC_CHECK_LIB(Xt, XtAppSetExitFlag, AC_DEFINE(HAVE_XTAPPSETEXITFLAG), , [$Xt_LIBS $X_LIBS $X_PRE_LIBS $Xp_LIBS $Xext_LIBS $X_EXTRA_LIBS -lX11]) fi fi #dnl ##### Check for t1lib. #smr_CHECK_LIB(t1, t1, [Type 1 font rasterizer], # T1_InitLib, t1lib.h, # -lm, $X_CFLAGS) # t1lib has some potential security holes, and hasn't been updated in # years -- if you really want to use it, uncomment the preceding lines, # and comment out the next two lines t1_LIBS="" t1_CFLAGS="" AC_SUBST(t1_LIBS) AC_SUBST(t1_CFLAGS) dnl ##### Check for FreeType 2.x. dnl ##### (Note: FT_Get_Name_Index was added in FT 2.0.5, and is dnl ##### the reason that Xpdf requires 2.0.5+.) smr_CHECK_LIB(freetype2, freetype, [FreeType2 font rasterizer - version 2.0.5+], FT_Get_Name_Index, ft2build.h, -lm) AC_SUBST(freetype2_LIBS) AC_SUBST(freetype2_CFLAGS) if test "x$smr_have_freetype2_library" = xyes; then AC_DEFINE(HAVE_FREETYPE_FREETYPE_H) AC_DEFINE(HAVE_SPLASH) fi dnl ##### Check for libpaper (Debian). smr_CHECK_LIB(libpaper, paper, [Debian libpaper], paperinit, paper.h) AC_SUBST(libpaper_LIBS) AC_SUBST(libpaper_CFLAGS) dnl ##### Disable X-specific stuff in top-level Makefile. if test -n "$no_x" -o "x$smr_have_Xm_library" != xyes -o "x$smr_have_freetype2_library" != xyes; then X="#" XPDF_TARGET="all-no-x" else X="" XPDF_TARGET="all" fi AC_SUBST(X) AC_SUBST(XPDF_TARGET) dnl ##### Write the makefiles. AC_OUTPUT(Makefile goo/Makefile fofi/Makefile splash/Makefile xpdf/Makefile) dnl ##### Warn user if X is missing. if test -n "$no_x" -o "x$smr_have_Xm_library" != xyes -o "x$smr_have_freetype2_library" != xyes; then if test -n "$no_x"; then AC_MSG_WARN([Couldn't find X]); fi if test "x$smr_have_Xm_library" != xyes; then AC_MSG_WARN([Couldn't find Motif]); fi if test "x$smr_have_freetype2_library" != xyes; then AC_MSG_WARN([Couldn't find FreeType]); fi AC_MSG_WARN([-- You will be able to compile pdftops, pdftotext, pdfinfo, pdffonts, pdfdetach, and pdfimages, but not xpdf or pdftoppm]) fi xpdf-3.03/COPYING0000644000076400007640000004307611622305345012760 0ustar dereknderekn GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 675 Mass Ave, Cambridge, MA 02139, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19yy name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. xpdf-3.03/splash/0000755000076400007640000000000011622305345013205 5ustar derekndereknxpdf-3.03/splash/SplashState.h0000644000076400007640000000576311622305345015624 0ustar dereknderekn//======================================================================== // // SplashState.h // //======================================================================== #ifndef SPLASHSTATE_H #define SPLASHSTATE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" class SplashPattern; class SplashScreen; class SplashClip; class SplashBitmap; //------------------------------------------------------------------------ // line cap values //------------------------------------------------------------------------ #define splashLineCapButt 0 #define splashLineCapRound 1 #define splashLineCapProjecting 2 //------------------------------------------------------------------------ // line join values //------------------------------------------------------------------------ #define splashLineJoinMiter 0 #define splashLineJoinRound 1 #define splashLineJoinBevel 2 //------------------------------------------------------------------------ // SplashState //------------------------------------------------------------------------ class SplashState { public: // Create a new state object, initialized with default settings. SplashState(int width, int height, GBool vectorAntialias, SplashScreenParams *screenParams); SplashState(int width, int height, GBool vectorAntialias, SplashScreen *screenA); // Copy a state object. SplashState *copy() { return new SplashState(this); } ~SplashState(); // Set the stroke pattern. This does not copy . void setStrokePattern(SplashPattern *strokePatternA); // Set the fill pattern. This does not copy . void setFillPattern(SplashPattern *fillPatternA); // Set the screen. This does not copy . void setScreen(SplashScreen *screenA); // Set the line dash pattern. This copies the array. void setLineDash(SplashCoord *lineDashA, int lineDashLengthA, SplashCoord lineDashPhaseA); // Set the soft mask bitmap. void setSoftMask(SplashBitmap *softMaskA); // Set the transfer function. void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); private: SplashState(SplashState *state); SplashCoord matrix[6]; SplashPattern *strokePattern; SplashPattern *fillPattern; SplashScreen *screen; SplashBlendFunc blendFunc; SplashCoord strokeAlpha; SplashCoord fillAlpha; SplashCoord lineWidth; int lineCap; int lineJoin; SplashCoord miterLimit; SplashCoord flatness; SplashCoord *lineDash; int lineDashLength; SplashCoord lineDashPhase; GBool strokeAdjust; SplashClip *clip; SplashBitmap *softMask; GBool deleteSoftMask; GBool inNonIsolatedGroup; Guchar rgbTransferR[256], rgbTransferG[256], rgbTransferB[256]; Guchar grayTransfer[256]; Guchar cmykTransferC[256], cmykTransferM[256], cmykTransferY[256], cmykTransferK[256]; Guint overprintMask; SplashState *next; // used by Splash class friend class Splash; }; #endif xpdf-3.03/splash/SplashFontEngine.cc0000644000076400007640000002020411622305345016721 0ustar dereknderekn//======================================================================== // // SplashFontEngine.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #if HAVE_T1LIB_H #include #endif #include #include #ifndef WIN32 # include #endif #include "gmem.h" #include "GString.h" #include "SplashMath.h" #include "SplashT1FontEngine.h" #include "SplashFTFontEngine.h" #include "SplashFontFile.h" #include "SplashFontFileID.h" #include "SplashFont.h" #include "SplashFontEngine.h" #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #endif //------------------------------------------------------------------------ // SplashFontEngine //------------------------------------------------------------------------ SplashFontEngine::SplashFontEngine( #if HAVE_T1LIB_H GBool enableT1lib, #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H GBool enableFreeType, Guint freeTypeFlags, #endif GBool aa) { int i; for (i = 0; i < splashFontCacheSize; ++i) { fontCache[i] = NULL; } #if HAVE_T1LIB_H if (enableT1lib) { t1Engine = SplashT1FontEngine::init(aa); } else { t1Engine = NULL; } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (enableFreeType) { ftEngine = SplashFTFontEngine::init(aa, freeTypeFlags); } else { ftEngine = NULL; } #endif } SplashFontEngine::~SplashFontEngine() { int i; for (i = 0; i < splashFontCacheSize; ++i) { if (fontCache[i]) { delete fontCache[i]; } } #if HAVE_T1LIB_H if (t1Engine) { delete t1Engine; } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (ftEngine) { delete ftEngine; } #endif } SplashFontFile *SplashFontEngine::getFontFile(SplashFontFileID *id) { SplashFontFile *fontFile; int i; for (i = 0; i < splashFontCacheSize; ++i) { if (fontCache[i]) { fontFile = fontCache[i]->getFontFile(); if (fontFile && fontFile->getID()->matches(id)) { return fontFile; } } } return NULL; } SplashFontFile *SplashFontEngine::loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_T1LIB_H if (!fontFile && t1Engine) { fontFile = t1Engine->loadType1Font(idA, fileName, deleteFile, enc); } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadType1Font(idA, fileName, deleteFile, enc); } #endif #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFontFile *SplashFontEngine::loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_T1LIB_H if (!fontFile && t1Engine) { fontFile = t1Engine->loadType1CFont(idA, fileName, deleteFile, enc); } #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadType1CFont(idA, fileName, deleteFile, enc); } #endif #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFontFile *SplashFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadOpenTypeT1CFont(idA, fileName, deleteFile, enc); } #endif #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFontFile *SplashFontEngine::loadCIDFont(SplashFontFileID *idA, char *fileName, GBool deleteFile) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadCIDFont(idA, fileName, deleteFile); } #endif #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFontFile *SplashFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, int *codeToGID, int codeToGIDLen) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadOpenTypeCFFFont(idA, fileName, deleteFile, codeToGID, codeToGIDLen); } #endif #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFontFile *SplashFontEngine::loadTrueTypeFont(SplashFontFileID *idA, char *fileName, int fontNum, GBool deleteFile, int *codeToGID, int codeToGIDLen, char *fontName) { SplashFontFile *fontFile; fontFile = NULL; #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H if (!fontFile && ftEngine) { fontFile = ftEngine->loadTrueTypeFont(idA, fileName, fontNum, deleteFile, codeToGID, codeToGIDLen); } #endif if (!fontFile) { gfree(codeToGID); } #ifndef WIN32 // delete the (temporary) font file -- with Unix hard link // semantics, this will remove the last link; otherwise it will // return an error, leaving the file to be deleted later (if // loadXYZFont failed, the file will always be deleted) if (deleteFile) { unlink(fontFile ? fontFile->fileName->getCString() : fileName); } #endif return fontFile; } SplashFont *SplashFontEngine::getFont(SplashFontFile *fontFile, SplashCoord *textMat, SplashCoord *ctm) { SplashCoord mat[4]; SplashFont *font; int i, j; mat[0] = textMat[0] * ctm[0] + textMat[1] * ctm[2]; mat[1] = -(textMat[0] * ctm[1] + textMat[1] * ctm[3]); mat[2] = textMat[2] * ctm[0] + textMat[3] * ctm[2]; mat[3] = -(textMat[2] * ctm[1] + textMat[3] * ctm[3]); if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.01)) { // avoid a singular (or close-to-singular) matrix mat[0] = 0.01; mat[1] = 0; mat[2] = 0; mat[3] = 0.01; } font = fontCache[0]; if (font && font->matches(fontFile, mat, textMat)) { return font; } for (i = 1; i < splashFontCacheSize; ++i) { font = fontCache[i]; if (font && font->matches(fontFile, mat, textMat)) { for (j = i; j > 0; --j) { fontCache[j] = fontCache[j-1]; } fontCache[0] = font; return font; } } font = fontFile->makeFont(mat, textMat); if (fontCache[splashFontCacheSize - 1]) { delete fontCache[splashFontCacheSize - 1]; } for (j = splashFontCacheSize - 1; j > 0; --j) { fontCache[j] = fontCache[j-1]; } fontCache[0] = font; return font; } xpdf-3.03/splash/SplashFont.h0000644000076400007640000000653111622305345015444 0ustar dereknderekn//======================================================================== // // SplashFont.h // //======================================================================== #ifndef SPLASHFONT_H #define SPLASHFONT_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "SplashTypes.h" struct SplashGlyphBitmap; struct SplashFontCacheTag; class SplashFontFile; class SplashPath; //------------------------------------------------------------------------ // Fractional positioning uses this many bits to the right of the // decimal points. #define splashFontFractionBits 2 #define splashFontFraction (1 << splashFontFractionBits) #define splashFontFractionMul \ ((SplashCoord)1 / (SplashCoord)splashFontFraction) //------------------------------------------------------------------------ // SplashFont //------------------------------------------------------------------------ class SplashFont { public: SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA, GBool aaA); // This must be called after the constructor, so that the subclass // constructor has a chance to compute the bbox. void initCache(); virtual ~SplashFont(); SplashFontFile *getFontFile() { return fontFile; } // Return true if matches the specified font file and matrix. GBool matches(SplashFontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA) { return fontFileA == fontFile && matA[0] == mat[0] && matA[1] == mat[1] && matA[2] == mat[2] && matA[3] == mat[3] && textMatA[0] == textMat[0] && textMatA[1] == textMat[1] && textMatA[2] == textMat[2] && textMatA[3] == textMat[3]; } // Get a glyph - this does a cache lookup first, and if not found, // creates a new bitmap and adds it to the cache. The and // values are splashFontFractionBits bits each, representing // the numerators of fractions in [0, 1), where the denominator is // splashFontFraction = 1 << splashFontFractionBits. Subclasses // should override this to zero out xFrac and/or yFrac if they don't // support fractional coordinates. virtual GBool getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Rasterize a glyph. The and values are the same // as described for getGlyph. virtual GBool makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) = 0; // Return the path for a glyph. virtual SplashPath *getGlyphPath(int c) = 0; // Return the font transform matrix. SplashCoord *getMatrix() { return mat; } // Return the glyph bounding box. void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } protected: SplashFontFile *fontFile; SplashCoord mat[4]; // font transform matrix // (text space -> device space) SplashCoord textMat[4]; // text transform matrix // (text space -> user space) GBool aa; // anti-aliasing int xMin, yMin, xMax, yMax; // glyph bounding box Guchar *cache; // glyph bitmap cache SplashFontCacheTag * // cache tags cacheTags; int glyphW, glyphH; // size of glyph bitmaps int glyphSize; // size of glyph bitmaps, in bytes int cacheSets; // number of sets in cache int cacheAssoc; // cache associativity (glyphs per set) }; #endif xpdf-3.03/splash/SplashErrorCodes.h0000644000076400007640000000156711622305345016611 0ustar dereknderekn//======================================================================== // // SplashErrorCodes.h // //======================================================================== #ifndef SPLASHERRORCODES_H #define SPLASHERRORCODES_H #include //------------------------------------------------------------------------ #define splashOk 0 // no error #define splashErrNoCurPt 1 // no current point #define splashErrEmptyPath 2 // zero points in path #define splashErrBogusPath 3 // only one point in subpath #define splashErrNoSave 4 // state stack is empty #define splashErrOpenFile 5 // couldn't open file #define splashErrNoGlyph 6 // couldn't get the requested glyph #define splashErrModeMismatch 7 // invalid combination of color modes #define splashErrSingularMatrix 8 // matrix is singular #endif xpdf-3.03/splash/SplashT1FontFile.h0000644000076400007640000000246011622305345016446 0ustar dereknderekn//======================================================================== // // SplashT1FontFile.h // //======================================================================== #ifndef SPLASHT1FONTFILE_H #define SPLASHT1FONTFILE_H #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashFontFile.h" class SplashT1FontEngine; //------------------------------------------------------------------------ // SplashT1FontFile //------------------------------------------------------------------------ class SplashT1FontFile: public SplashFontFile { public: static SplashFontFile *loadType1Font(SplashT1FontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, const char **encA); virtual ~SplashT1FontFile(); // Create a new SplashT1Font, i.e., a scaled instance of this font // file. virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat); private: SplashT1FontFile(SplashT1FontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, int t1libIDA, const char **encA, char *encStrA); SplashT1FontEngine *engine; int t1libID; // t1lib font ID const char **enc; char *encStr; friend class SplashT1Font; }; #endif // HAVE_T1LIB_H #endif xpdf-3.03/splash/SplashFontFileID.cc0000644000076400007640000000103411622305345016610 0ustar dereknderekn//======================================================================== // // SplashFontFileID.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "SplashFontFileID.h" //------------------------------------------------------------------------ // SplashFontFileID //------------------------------------------------------------------------ SplashFontFileID::SplashFontFileID() { } SplashFontFileID::~SplashFontFileID() { } xpdf-3.03/splash/SplashFontFile.h0000644000076400007640000000237711622305345016250 0ustar dereknderekn//======================================================================== // // SplashFontFile.h // //======================================================================== #ifndef SPLASHFONTFILE_H #define SPLASHFONTFILE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "SplashTypes.h" class GString; class SplashFontEngine; class SplashFont; class SplashFontFileID; //------------------------------------------------------------------------ // SplashFontFile //------------------------------------------------------------------------ class SplashFontFile { public: virtual ~SplashFontFile(); // Create a new SplashFont, i.e., a scaled instance of this font // file. virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat) = 0; // Get the font file ID. SplashFontFileID *getID() { return id; } // Increment the reference count. void incRefCnt(); // Decrement the reference count. If the new value is zero, delete // the SplashFontFile object. void decRefCnt(); protected: SplashFontFile(SplashFontFileID *idA, char *fileNameA, GBool deleteFileA); SplashFontFileID *id; GString *fileName; GBool deleteFile; int refCnt; friend class SplashFontEngine; }; #endif xpdf-3.03/splash/Makefile.dep0000644000076400007640000000000011622305345015402 0ustar derekndereknxpdf-3.03/splash/vms_make.com0000644000076400007640000000000011622305345015475 0ustar derekndereknxpdf-3.03/splash/SplashScreen.cc0000644000076400007640000002275711622305345016123 0ustar dereknderekn//======================================================================== // // SplashScreen.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #if HAVE_STD_SORT #include #endif #include "gmem.h" #include "SplashMath.h" #include "SplashScreen.h" //------------------------------------------------------------------------ static SplashScreenParams defaultParams = { splashScreenDispersed, // type 2, // size 2, // dotRadius 1.0, // gamma 0.0, // blackThreshold 1.0 // whiteThreshold }; //------------------------------------------------------------------------ struct SplashScreenPoint { int x, y; int dist; }; #if HAVE_STD_SORT struct cmpDistancesFunctor { bool operator()(const SplashScreenPoint &p0, const SplashScreenPoint &p1) { return p0.dist < p1.dist; } }; #else // HAVE_STD_SORT static int cmpDistances(const void *p0, const void *p1) { return ((SplashScreenPoint *)p0)->dist - ((SplashScreenPoint *)p1)->dist; } #endif //------------------------------------------------------------------------ // SplashScreen //------------------------------------------------------------------------ // If is true, this generates a 45 degree screen using a // circular dot spot function. DPI = resolution / ((size / 2) * // sqrt(2)). If is false, this generates an optimal // threshold matrix using recursive tesselation. Gamma correction // (gamma = 1 / 1.33) is also computed here. SplashScreen::SplashScreen(SplashScreenParams *params) { Guchar u; int black, white, i; if (!params) { params = &defaultParams; } // size must be a power of 2, and at least 2 for (size = 2, log2Size = 1; size < params->size; size <<= 1, ++log2Size) ; switch (params->type) { case splashScreenDispersed: mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); buildDispersedMatrix(size/2, size/2, 1, size/2, 1); break; case splashScreenClustered: mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); buildClusteredMatrix(); break; case splashScreenStochasticClustered: // size must be at least 2*r while (size < (params->dotRadius << 1)) { size <<= 1; ++log2Size; } mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); buildSCDMatrix(params->dotRadius); break; } sizeM1 = size - 1; // do gamma correction and compute minVal/maxVal minVal = 255; maxVal = 0; black = splashRound((SplashCoord)255.0 * params->blackThreshold); if (black < 1) { black = 1; } white = splashRound((SplashCoord)255.0 * params->whiteThreshold); if (white > 255) { white = 255; } for (i = 0; i < size * size; ++i) { u = splashRound((SplashCoord)255.0 * splashPow((SplashCoord)mat[i] / 255.0, params->gamma)); if (u < black) { u = (Guchar)black; } else if (u >= white) { u = (Guchar)white; } mat[i] = u; if (u < minVal) { minVal = u; } else if (u > maxVal) { maxVal = u; } } } void SplashScreen::buildDispersedMatrix(int i, int j, int val, int delta, int offset) { if (delta == 0) { // map values in [1, size^2] --> [1, 255] mat[(i << log2Size) + j] = 1 + (254 * (val - 1)) / (size * size - 1); } else { buildDispersedMatrix(i, j, val, delta / 2, 4*offset); buildDispersedMatrix((i + delta) % size, (j + delta) % size, val + offset, delta / 2, 4*offset); buildDispersedMatrix((i + delta) % size, j, val + 2*offset, delta / 2, 4*offset); buildDispersedMatrix((i + 2*delta) % size, (j + delta) % size, val + 3*offset, delta / 2, 4*offset); } } void SplashScreen::buildClusteredMatrix() { SplashCoord *dist; SplashCoord u, v, d; Guchar val; int size2, x, y, x1, y1, i; size2 = size >> 1; // initialize the threshold matrix for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { mat[(y << log2Size) + x] = 0; } } // build the distance matrix dist = (SplashCoord *)gmallocn(size * size2, sizeof(SplashCoord)); for (y = 0; y < size2; ++y) { for (x = 0; x < size2; ++x) { if (x + y < size2 - 1) { u = (SplashCoord)x + 0.5 - 0; v = (SplashCoord)y + 0.5 - 0; } else { u = (SplashCoord)x + 0.5 - (SplashCoord)size2; v = (SplashCoord)y + 0.5 - (SplashCoord)size2; } dist[y * size2 + x] = u*u + v*v; } } for (y = 0; y < size2; ++y) { for (x = 0; x < size2; ++x) { if (x < y) { u = (SplashCoord)x + 0.5 - 0; v = (SplashCoord)y + 0.5 - (SplashCoord)size2; } else { u = (SplashCoord)x + 0.5 - (SplashCoord)size2; v = (SplashCoord)y + 0.5 - 0; } dist[(size2 + y) * size2 + x] = u*u + v*v; } } // build the threshold matrix x1 = y1 = 0; // make gcc happy for (i = 0; i < size * size2; ++i) { d = -1; for (y = 0; y < size; ++y) { for (x = 0; x < size2; ++x) { if (mat[(y << log2Size) + x] == 0 && dist[y * size2 + x] > d) { x1 = x; y1 = y; d = dist[y1 * size2 + x1]; } } } // map values in [0, 2*size*size2-1] --> [1, 255] val = 1 + (254 * (2*i)) / (2*size*size2 - 1); mat[(y1 << log2Size) + x1] = val; val = 1 + (254 * (2*i+1)) / (2*size*size2 - 1); if (y1 < size2) { mat[((y1 + size2) << log2Size) + x1 + size2] = val; } else { mat[((y1 - size2) << log2Size) + x1 + size2] = val; } } gfree(dist); } // Compute the distance between two points on a toroid. int SplashScreen::distance(int x0, int y0, int x1, int y1) { int dx0, dx1, dx, dy0, dy1, dy; dx0 = abs(x0 - x1); dx1 = size - dx0; dx = dx0 < dx1 ? dx0 : dx1; dy0 = abs(y0 - y1); dy1 = size - dy0; dy = dy0 < dy1 ? dy0 : dy1; return dx * dx + dy * dy; } // Algorithm taken from: // Victor Ostromoukhov and Roger D. Hersch, "Stochastic Clustered-Dot // Dithering" in Color Imaging: Device-Independent Color, Color // Hardcopy, and Graphic Arts IV, SPIE Vol. 3648, pp. 496-505, 1999. void SplashScreen::buildSCDMatrix(int r) { SplashScreenPoint *dots, *pts; int dotsLen, dotsSize; char *tmpl; char *grid; int *region, *dist; int x, y, xx, yy, x0, x1, y0, y1, i, j, d, iMin, dMin, n; //~ this should probably happen somewhere else srand(123); // generate the random space-filling curve pts = (SplashScreenPoint *)gmallocn(size * size, sizeof(SplashScreenPoint)); i = 0; for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { pts[i].x = x; pts[i].y = y; ++i; } } for (i = 0; i < size * size; ++i) { j = i + (int)((double)(size * size - i) * (double)rand() / ((double)RAND_MAX + 1.0)); x = pts[i].x; y = pts[i].y; pts[i].x = pts[j].x; pts[i].y = pts[j].y; pts[j].x = x; pts[j].y = y; } // construct the circle template tmpl = (char *)gmallocn((r+1)*(r+1), sizeof(char)); for (y = 0; y <= r; ++y) { for (x = 0; x <= r; ++x) { tmpl[y*(r+1) + x] = (x * y <= r * r) ? 1 : 0; } } // mark all grid cells as free grid = (char *)gmallocn(size * size, sizeof(char)); for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { grid[(y << log2Size) + x] = 0; } } // walk the space-filling curve, adding dots dotsLen = 0; dotsSize = 32; dots = (SplashScreenPoint *)gmallocn(dotsSize, sizeof(SplashScreenPoint)); for (i = 0; i < size * size; ++i) { x = pts[i].x; y = pts[i].y; if (!grid[(y << log2Size) + x]) { if (dotsLen == dotsSize) { dotsSize *= 2; dots = (SplashScreenPoint *)greallocn(dots, dotsSize, sizeof(SplashScreenPoint)); } dots[dotsLen++] = pts[i]; for (yy = 0; yy <= r; ++yy) { y0 = (y + yy) % size; y1 = (y - yy + size) % size; for (xx = 0; xx <= r; ++xx) { if (tmpl[yy*(r+1) + xx]) { x0 = (x + xx) % size; x1 = (x - xx + size) % size; grid[(y0 << log2Size) + x0] = 1; grid[(y0 << log2Size) + x1] = 1; grid[(y1 << log2Size) + x0] = 1; grid[(y1 << log2Size) + x1] = 1; } } } } } gfree(tmpl); gfree(grid); // assign each cell to a dot, compute distance to center of dot region = (int *)gmallocn(size * size, sizeof(int)); dist = (int *)gmallocn(size * size, sizeof(int)); for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { iMin = 0; dMin = distance(dots[0].x, dots[0].y, x, y); for (i = 1; i < dotsLen; ++i) { d = distance(dots[i].x, dots[i].y, x, y); if (d < dMin) { iMin = i; dMin = d; } } region[(y << log2Size) + x] = iMin; dist[(y << log2Size) + x] = dMin; } } // compute threshold values for (i = 0; i < dotsLen; ++i) { n = 0; for (y = 0; y < size; ++y) { for (x = 0; x < size; ++x) { if (region[(y << log2Size) + x] == i) { pts[n].x = x; pts[n].y = y; pts[n].dist = distance(dots[i].x, dots[i].y, x, y); ++n; } } } #if HAVE_STD_SORT std::sort(pts, pts + n, cmpDistancesFunctor()); #else qsort(pts, n, sizeof(SplashScreenPoint), &cmpDistances); #endif for (j = 0; j < n; ++j) { // map values in [0 .. n-1] --> [255 .. 1] mat[(pts[j].y << log2Size) + pts[j].x] = 255 - (254 * j) / (n - 1); } } gfree(pts); gfree(region); gfree(dist); gfree(dots); } SplashScreen::SplashScreen(SplashScreen *screen) { size = screen->size; sizeM1 = screen->sizeM1; log2Size = screen->log2Size; mat = (Guchar *)gmallocn(size * size, sizeof(Guchar)); memcpy(mat, screen->mat, size * size * sizeof(Guchar)); minVal = screen->minVal; maxVal = screen->maxVal; } SplashScreen::~SplashScreen() { gfree(mat); } xpdf-3.03/splash/Splash.cc0000644000076400007640000040744411622305345014763 0ustar dereknderekn//======================================================================== // // Splash.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gmem.h" #include "SplashErrorCodes.h" #include "SplashMath.h" #include "SplashBitmap.h" #include "SplashState.h" #include "SplashPath.h" #include "SplashXPath.h" #include "SplashXPathScanner.h" #include "SplashPattern.h" #include "SplashScreen.h" #include "SplashFont.h" #include "SplashGlyphBitmap.h" #include "Splash.h" //------------------------------------------------------------------------ #define splashAAGamma 1.5 // distance of Bezier control point from center for circle approximation // = (4 * (sqrt(2) - 1) / 3) * r #define bezierCircle ((SplashCoord)0.55228475) #define bezierCircle2 ((SplashCoord)(0.5 * 0.55228475)) // Divide a 16-bit value (in [0, 255*255]) by 255, returning an 8-bit result. static inline Guchar div255(int x) { return (Guchar)((x + (x >> 8) + 0x80) >> 8); } // Clip x to lie in [0, 255]. static inline Guchar clip255(int x) { return x < 0 ? 0 : x > 255 ? 255 : x; } // The PDF spec says that all pixels whose *centers* lie within the // image target region get painted, so we want to round n+0.5 down to // n. But this causes problems, e.g., with PDF files that fill a // rectangle with black and then draw an image to the exact same // rectangle, so we instead use the fill scan conversion rule. // However, the correct rule works better for glyphs, so we also // provide that option in fillImageMask. #if 0 static inline int imgCoordMungeLower(SplashCoord x) { return splashCeil(x + 0.5) - 1; } static inline int imgCoordMungeUpper(SplashCoord x) { return splashCeil(x + 0.5) - 1; } #else static inline int imgCoordMungeLower(SplashCoord x) { return splashFloor(x); } static inline int imgCoordMungeUpper(SplashCoord x) { return splashFloor(x) + 1; } static inline int imgCoordMungeLowerC(SplashCoord x, GBool glyphMode) { return glyphMode ? (splashCeil(x + 0.5) - 1) : splashFloor(x); } static inline int imgCoordMungeUpperC(SplashCoord x, GBool glyphMode) { return glyphMode ? (splashCeil(x + 0.5) - 1) : (splashFloor(x) + 1); } #endif // Used by drawImage and fillImageMask to divide the target // quadrilateral into sections. struct ImageSection { int y0, y1; // actual y range int ia0, ia1; // vertex indices for edge A int ib0, ib1; // vertex indices for edge A SplashCoord xa0, ya0, xa1, ya1; // edge A SplashCoord dxdya; // slope of edge A SplashCoord xb0, yb0, xb1, yb1; // edge B SplashCoord dxdyb; // slope of edge B }; //------------------------------------------------------------------------ // SplashPipe //------------------------------------------------------------------------ #define splashPipeMaxStages 9 struct SplashPipe { // pixel coordinates int x, y; // source pattern SplashPattern *pattern; // source alpha and color Guchar aInput; GBool usesShape; SplashColorPtr cSrc; SplashColor cSrcVal; // non-isolated group alpha0 Guchar *alpha0Ptr; // soft mask SplashColorPtr softMaskPtr; // destination alpha and color SplashColorPtr destColorPtr; int destColorMask; Guchar *destAlphaPtr; // shape Guchar shape; // result alpha and color GBool noTransparency; SplashPipeResultColorCtrl resultColorCtrl; // non-isolated group correction GBool nonIsolatedGroup; // the "run" function void (Splash::*run)(SplashPipe *pipe); }; SplashPipeResultColorCtrl Splash::pipeResultColorNoAlphaBlend[] = { splashPipeResultColorNoAlphaBlendMono, splashPipeResultColorNoAlphaBlendMono, splashPipeResultColorNoAlphaBlendRGB, splashPipeResultColorNoAlphaBlendRGB #if SPLASH_CMYK , splashPipeResultColorNoAlphaBlendCMYK #endif }; SplashPipeResultColorCtrl Splash::pipeResultColorAlphaNoBlend[] = { splashPipeResultColorAlphaNoBlendMono, splashPipeResultColorAlphaNoBlendMono, splashPipeResultColorAlphaNoBlendRGB, splashPipeResultColorAlphaNoBlendRGB #if SPLASH_CMYK , splashPipeResultColorAlphaNoBlendCMYK #endif }; SplashPipeResultColorCtrl Splash::pipeResultColorAlphaBlend[] = { splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendRGB, splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , splashPipeResultColorAlphaBlendCMYK #endif }; //------------------------------------------------------------------------ static void blendXor(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm) { int i; for (i = 0; i < splashColorModeNComps[cm]; ++i) { blend[i] = src[i] ^ dest[i]; } } //------------------------------------------------------------------------ // modified region //------------------------------------------------------------------------ void Splash::clearModRegion() { modXMin = bitmap->getWidth(); modYMin = bitmap->getHeight(); modXMax = -1; modYMax = -1; } inline void Splash::updateModX(int x) { if (x < modXMin) { modXMin = x; } if (x > modXMax) { modXMax = x; } } inline void Splash::updateModY(int y) { if (y < modYMin) { modYMin = y; } if (y > modYMax) { modYMax = y; } } //------------------------------------------------------------------------ // pipeline //------------------------------------------------------------------------ inline void Splash::pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, Guchar aInput, GBool usesShape, GBool nonIsolatedGroup) { pipeSetXY(pipe, x, y); pipe->pattern = NULL; // source color if (pattern) { if (pattern->isStatic()) { pattern->getColor(x, y, pipe->cSrcVal); } else { pipe->pattern = pattern; } pipe->cSrc = pipe->cSrcVal; } else { pipe->cSrc = cSrc; } // source alpha pipe->aInput = aInput; pipe->usesShape = usesShape; // result alpha if (aInput == 255 && !state->softMask && !usesShape && !state->inNonIsolatedGroup && !nonIsolatedGroup) { pipe->noTransparency = gTrue; } else { pipe->noTransparency = gFalse; } // result color if (pipe->noTransparency) { // the !state->blendFunc case is handled separately in pipeRun pipe->resultColorCtrl = pipeResultColorNoAlphaBlend[bitmap->mode]; } else if (!state->blendFunc) { pipe->resultColorCtrl = pipeResultColorAlphaNoBlend[bitmap->mode]; } else { pipe->resultColorCtrl = pipeResultColorAlphaBlend[bitmap->mode]; } // non-isolated group correction pipe->nonIsolatedGroup = nonIsolatedGroup; // select the 'run' function pipe->run = &Splash::pipeRun; if (!pipe->pattern && pipe->noTransparency && !state->blendFunc) { if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleMono1; } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleMono8; } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleRGB8; } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleBGR8; #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunSimpleCMYK8; #endif } } else if (!pipe->pattern && !pipe->noTransparency && !state->softMask && pipe->usesShape && !(state->inNonIsolatedGroup && alpha0Bitmap->alpha) && !state->blendFunc && !pipe->nonIsolatedGroup) { if (bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAAMono1; } else if (bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAAMono8; } else if (bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAARGB8; } else if (bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAABGR8; #if SPLASH_CMYK } else if (bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { pipe->run = &Splash::pipeRunAACMYK8; #endif } } } // general case void Splash::pipeRun(SplashPipe *pipe) { Guchar aSrc, aDest, alphaI, alphaIm1, alpha0, aResult; SplashColor cSrcNonIso, cDest, cBlend; SplashColorPtr cSrc; Guchar cResult0, cResult1, cResult2, cResult3; int t; #if SPLASH_CMYK SplashColor cSrc2, cDest2; #endif //----- source color // static pattern: handled in pipeInit // fixed color: handled in pipeInit // dynamic pattern if (pipe->pattern) { pipe->pattern->getColor(pipe->x, pipe->y, pipe->cSrcVal); } if (pipe->noTransparency && !state->blendFunc) { //----- write destination pixel switch (bitmap->mode) { case splashModeMono1: cResult0 = state->grayTransfer[pipe->cSrc[0]]; if (state->screen->test(pipe->x, pipe->y, cResult0)) { *pipe->destColorPtr |= pipe->destColorMask; } else { *pipe->destColorPtr &= ~pipe->destColorMask; } if (!(pipe->destColorMask >>= 1)) { pipe->destColorMask = 0x80; ++pipe->destColorPtr; } break; case splashModeMono8: *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; break; case splashModeRGB8: *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; break; case splashModeBGR8: *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; break; #if SPLASH_CMYK case splashModeCMYK8: if (state->overprintMask & 1) { pipe->destColorPtr[0] = state->cmykTransferC[pipe->cSrc[0]]; } if (state->overprintMask & 2) { pipe->destColorPtr[1] = state->cmykTransferM[pipe->cSrc[1]]; } if (state->overprintMask & 4) { pipe->destColorPtr[2] = state->cmykTransferY[pipe->cSrc[2]]; } if (state->overprintMask & 8) { pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]]; } pipe->destColorPtr += 4; break; #endif } if (pipe->destAlphaPtr) { *pipe->destAlphaPtr++ = 255; } } else { //----- read destination pixel switch (bitmap->mode) { case splashModeMono1: cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00; break; case splashModeMono8: cDest[0] = *pipe->destColorPtr; break; case splashModeRGB8: cDest[0] = pipe->destColorPtr[0]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[2]; break; case splashModeBGR8: cDest[0] = pipe->destColorPtr[2]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[0]; break; #if SPLASH_CMYK case splashModeCMYK8: cDest[0] = pipe->destColorPtr[0]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[2]; cDest[3] = pipe->destColorPtr[3]; break; #endif } if (pipe->destAlphaPtr) { aDest = *pipe->destAlphaPtr; } else { aDest = 0xff; } //----- source alpha if (state->softMask) { if (pipe->usesShape) { aSrc = div255(div255(pipe->aInput * *pipe->softMaskPtr++) * pipe->shape); } else { aSrc = div255(pipe->aInput * *pipe->softMaskPtr++); } } else if (pipe->usesShape) { aSrc = div255(pipe->aInput * pipe->shape); } else { aSrc = pipe->aInput; } //----- non-isolated group correction if (pipe->nonIsolatedGroup) { // This path is only used when Splash::composite() is called to // composite a non-isolated group onto the backdrop. In this // case, pipe->shape is the source (group) alpha. if (pipe->shape == 0) { // this value will be multiplied by zero later, so it doesn't // matter what we use cSrc = pipe->cSrc; } else { t = (aDest * 255) / pipe->shape - aDest; switch (bitmap->mode) { #if SPLASH_CMYK case splashModeCMYK8: cSrcNonIso[3] = clip255(pipe->cSrc[3] + ((pipe->cSrc[3] - cDest[3]) * t) / 255); #endif case splashModeRGB8: case splashModeBGR8: cSrcNonIso[2] = clip255(pipe->cSrc[2] + ((pipe->cSrc[2] - cDest[2]) * t) / 255); cSrcNonIso[1] = clip255(pipe->cSrc[1] + ((pipe->cSrc[1] - cDest[1]) * t) / 255); case splashModeMono1: case splashModeMono8: cSrcNonIso[0] = clip255(pipe->cSrc[0] + ((pipe->cSrc[0] - cDest[0]) * t) / 255); break; } cSrc = cSrcNonIso; } } else { cSrc = pipe->cSrc; } //----- blend function if (state->blendFunc) { #if SPLASH_CMYK if (bitmap->mode == splashModeCMYK8) { // convert colors to additive cSrc2[0] = 0xff - cSrc[0]; cSrc2[1] = 0xff - cSrc[1]; cSrc2[2] = 0xff - cSrc[2]; cSrc2[3] = 0xff - cSrc[3]; cDest2[0] = 0xff - cDest[0]; cDest2[1] = 0xff - cDest[1]; cDest2[2] = 0xff - cDest[2]; cDest2[3] = 0xff - cDest[3]; (*state->blendFunc)(cSrc2, cDest2, cBlend, bitmap->mode); // convert result back to subtractive cBlend[0] = 0xff - cBlend[0]; cBlend[1] = 0xff - cBlend[1]; cBlend[2] = 0xff - cBlend[2]; cBlend[3] = 0xff - cBlend[3]; } else #endif (*state->blendFunc)(cSrc, cDest, cBlend, bitmap->mode); } //----- result alpha and non-isolated group element correction if (pipe->noTransparency) { alphaI = alphaIm1 = aResult = 255; } else { aResult = aSrc + aDest - div255(aSrc * aDest); // alphaI = alpha_i // alphaIm1 = alpha_(i-1) if (pipe->alpha0Ptr) { alpha0 = *pipe->alpha0Ptr++; alphaI = aResult + alpha0 - div255(aResult * alpha0); alphaIm1 = alpha0 + aDest - div255(alpha0 * aDest); } else { alphaI = aResult; alphaIm1 = aDest; } } //----- result color cResult0 = cResult1 = cResult2 = cResult3 = 0; // make gcc happy switch (pipe->resultColorCtrl) { case splashPipeResultColorNoAlphaBlendMono: cResult0 = state->grayTransfer[div255((255 - aDest) * cSrc[0] + aDest * cBlend[0])]; break; case splashPipeResultColorNoAlphaBlendRGB: cResult0 = state->rgbTransferR[div255((255 - aDest) * cSrc[0] + aDest * cBlend[0])]; cResult1 = state->rgbTransferG[div255((255 - aDest) * cSrc[1] + aDest * cBlend[1])]; cResult2 = state->rgbTransferB[div255((255 - aDest) * cSrc[2] + aDest * cBlend[2])]; break; #if SPLASH_CMYK case splashPipeResultColorNoAlphaBlendCMYK: cResult0 = state->cmykTransferC[div255((255 - aDest) * cSrc[0] + aDest * cBlend[0])]; cResult1 = state->cmykTransferM[div255((255 - aDest) * cSrc[1] + aDest * cBlend[1])]; cResult2 = state->cmykTransferY[div255((255 - aDest) * cSrc[2] + aDest * cBlend[2])]; cResult3 = state->cmykTransferK[div255((255 - aDest) * cSrc[3] + aDest * cBlend[3])]; break; #endif case splashPipeResultColorAlphaNoBlendMono: if (alphaI == 0) { cResult0 = 0; } else { cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI]; } break; case splashPipeResultColorAlphaNoBlendRGB: if (alphaI == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; } else { cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI]; cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) / alphaI]; cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) / alphaI]; } break; #if SPLASH_CMYK case splashPipeResultColorAlphaNoBlendCMYK: if (alphaI == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; cResult3 = 0; } else { cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] + aSrc * cSrc[0]) / alphaI]; cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] + aSrc * cSrc[1]) / alphaI]; cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] + aSrc * cSrc[2]) / alphaI]; cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] + aSrc * cSrc[3]) / alphaI]; } break; #endif case splashPipeResultColorAlphaBlendMono: if (alphaI == 0) { cResult0 = 0; } else { cResult0 = state->grayTransfer[((alphaI - aSrc) * cDest[0] + aSrc * ((255 - alphaIm1) * cSrc[0] + alphaIm1 * cBlend[0]) / 255) / alphaI]; } break; case splashPipeResultColorAlphaBlendRGB: if (alphaI == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; } else { cResult0 = state->rgbTransferR[((alphaI - aSrc) * cDest[0] + aSrc * ((255 - alphaIm1) * cSrc[0] + alphaIm1 * cBlend[0]) / 255) / alphaI]; cResult1 = state->rgbTransferG[((alphaI - aSrc) * cDest[1] + aSrc * ((255 - alphaIm1) * cSrc[1] + alphaIm1 * cBlend[1]) / 255) / alphaI]; cResult2 = state->rgbTransferB[((alphaI - aSrc) * cDest[2] + aSrc * ((255 - alphaIm1) * cSrc[2] + alphaIm1 * cBlend[2]) / 255) / alphaI]; } break; #if SPLASH_CMYK case splashPipeResultColorAlphaBlendCMYK: if (alphaI == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; cResult3 = 0; } else { cResult0 = state->cmykTransferC[((alphaI - aSrc) * cDest[0] + aSrc * ((255 - alphaIm1) * cSrc[0] + alphaIm1 * cBlend[0]) / 255) / alphaI]; cResult1 = state->cmykTransferM[((alphaI - aSrc) * cDest[1] + aSrc * ((255 - alphaIm1) * cSrc[1] + alphaIm1 * cBlend[1]) / 255) / alphaI]; cResult2 = state->cmykTransferY[((alphaI - aSrc) * cDest[2] + aSrc * ((255 - alphaIm1) * cSrc[2] + alphaIm1 * cBlend[2]) / 255) / alphaI]; cResult3 = state->cmykTransferK[((alphaI - aSrc) * cDest[3] + aSrc * ((255 - alphaIm1) * cSrc[3] + alphaIm1 * cBlend[3]) / 255) / alphaI]; } break; #endif } //----- write destination pixel switch (bitmap->mode) { case splashModeMono1: if (state->screen->test(pipe->x, pipe->y, cResult0)) { *pipe->destColorPtr |= pipe->destColorMask; } else { *pipe->destColorPtr &= ~pipe->destColorMask; } if (!(pipe->destColorMask >>= 1)) { pipe->destColorMask = 0x80; ++pipe->destColorPtr; } break; case splashModeMono8: *pipe->destColorPtr++ = cResult0; break; case splashModeRGB8: *pipe->destColorPtr++ = cResult0; *pipe->destColorPtr++ = cResult1; *pipe->destColorPtr++ = cResult2; break; case splashModeBGR8: *pipe->destColorPtr++ = cResult2; *pipe->destColorPtr++ = cResult1; *pipe->destColorPtr++ = cResult0; break; #if SPLASH_CMYK case splashModeCMYK8: if (state->overprintMask & 1) { pipe->destColorPtr[0] = cResult0; } if (state->overprintMask & 2) { pipe->destColorPtr[1] = cResult1; } if (state->overprintMask & 4) { pipe->destColorPtr[2] = cResult2; } if (state->overprintMask & 8) { pipe->destColorPtr[3] = cResult3; } pipe->destColorPtr += 4; break; #endif } if (pipe->destAlphaPtr) { *pipe->destAlphaPtr++ = aResult; } } ++pipe->x; } // special case: // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr) { void Splash::pipeRunSimpleMono1(SplashPipe *pipe) { Guchar cResult0; //----- write destination pixel cResult0 = state->grayTransfer[pipe->cSrc[0]]; if (state->screen->test(pipe->x, pipe->y, cResult0)) { *pipe->destColorPtr |= pipe->destColorMask; } else { *pipe->destColorPtr &= ~pipe->destColorMask; } if (!(pipe->destColorMask >>= 1)) { pipe->destColorMask = 0x80; ++pipe->destColorPtr; } ++pipe->x; } // special case: // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeMono8 && pipe->destAlphaPtr) { void Splash::pipeRunSimpleMono8(SplashPipe *pipe) { //----- write destination pixel *pipe->destColorPtr++ = state->grayTransfer[pipe->cSrc[0]]; *pipe->destAlphaPtr++ = 255; ++pipe->x; } // special case: // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr) { void Splash::pipeRunSimpleRGB8(SplashPipe *pipe) { //----- write destination pixel *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; *pipe->destAlphaPtr++ = 255; ++pipe->x; } // special case: // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr) { void Splash::pipeRunSimpleBGR8(SplashPipe *pipe) { //----- write destination pixel *pipe->destColorPtr++ = state->rgbTransferB[pipe->cSrc[2]]; *pipe->destColorPtr++ = state->rgbTransferG[pipe->cSrc[1]]; *pipe->destColorPtr++ = state->rgbTransferR[pipe->cSrc[0]]; *pipe->destAlphaPtr++ = 255; ++pipe->x; } #if SPLASH_CMYK // special case: // !pipe->pattern && pipe->noTransparency && !state->blendFunc && // bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr) { void Splash::pipeRunSimpleCMYK8(SplashPipe *pipe) { //----- write destination pixel if (state->overprintMask & 1) { pipe->destColorPtr[0] = state->cmykTransferC[pipe->cSrc[0]]; } if (state->overprintMask & 2) { pipe->destColorPtr[1] = state->cmykTransferM[pipe->cSrc[1]]; } if (state->overprintMask & 4) { pipe->destColorPtr[2] = state->cmykTransferY[pipe->cSrc[2]]; } if (state->overprintMask & 8) { pipe->destColorPtr[3] = state->cmykTransferK[pipe->cSrc[3]]; } pipe->destColorPtr += 4; *pipe->destAlphaPtr++ = 255; ++pipe->x; } #endif // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeMono1 && !pipe->destAlphaPtr void Splash::pipeRunAAMono1(SplashPipe *pipe) { Guchar aSrc; SplashColor cDest; Guchar cResult0; //----- read destination pixel cDest[0] = (*pipe->destColorPtr & pipe->destColorMask) ? 0xff : 0x00; //----- source alpha aSrc = div255(pipe->aInput * pipe->shape); //----- result color // note: aDest = alpha2 = aResult = 0xff cResult0 = state->grayTransfer[(Guchar)div255((0xff - aSrc) * cDest[0] + aSrc * pipe->cSrc[0])]; //----- write destination pixel if (state->screen->test(pipe->x, pipe->y, cResult0)) { *pipe->destColorPtr |= pipe->destColorMask; } else { *pipe->destColorPtr &= ~pipe->destColorMask; } if (!(pipe->destColorMask >>= 1)) { pipe->destColorMask = 0x80; ++pipe->destColorPtr; } ++pipe->x; } // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeMono8 && pipe->destAlphaPtr void Splash::pipeRunAAMono8(SplashPipe *pipe) { Guchar aSrc, aDest, alpha2, aResult; SplashColor cDest; Guchar cResult0; //----- read destination pixel cDest[0] = *pipe->destColorPtr; aDest = *pipe->destAlphaPtr; //----- source alpha aSrc = div255(pipe->aInput * pipe->shape); //----- result alpha and non-isolated group element correction aResult = aSrc + aDest - div255(aSrc * aDest); alpha2 = aResult; //----- result color if (alpha2 == 0) { cResult0 = 0; } else { cResult0 = state->grayTransfer[(Guchar)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)]; } //----- write destination pixel *pipe->destColorPtr++ = cResult0; *pipe->destAlphaPtr++ = aResult; ++pipe->x; } // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeRGB8 && pipe->destAlphaPtr void Splash::pipeRunAARGB8(SplashPipe *pipe) { Guchar aSrc, aDest, alpha2, aResult; SplashColor cDest; Guchar cResult0, cResult1, cResult2; //----- read destination pixel cDest[0] = pipe->destColorPtr[0]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[2]; aDest = *pipe->destAlphaPtr; //----- source alpha aSrc = div255(pipe->aInput * pipe->shape); //----- result alpha and non-isolated group element correction aResult = aSrc + aDest - div255(aSrc * aDest); alpha2 = aResult; //----- result color if (alpha2 == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; } else { cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)]; cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)]; cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + aSrc * pipe->cSrc[2]) / alpha2)]; } //----- write destination pixel *pipe->destColorPtr++ = cResult0; *pipe->destColorPtr++ = cResult1; *pipe->destColorPtr++ = cResult2; *pipe->destAlphaPtr++ = aResult; ++pipe->x; } // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeBGR8 && pipe->destAlphaPtr void Splash::pipeRunAABGR8(SplashPipe *pipe) { Guchar aSrc, aDest, alpha2, aResult; SplashColor cDest; Guchar cResult0, cResult1, cResult2; //----- read destination pixel cDest[0] = pipe->destColorPtr[2]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[0]; aDest = *pipe->destAlphaPtr; //----- source alpha aSrc = div255(pipe->aInput * pipe->shape); //----- result alpha and non-isolated group element correction aResult = aSrc + aDest - div255(aSrc * aDest); alpha2 = aResult; //----- result color if (alpha2 == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; } else { cResult0 = state->rgbTransferR[(Guchar)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)]; cResult1 = state->rgbTransferG[(Guchar)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)]; cResult2 = state->rgbTransferB[(Guchar)(((alpha2 - aSrc) * cDest[2] + aSrc * pipe->cSrc[2]) / alpha2)]; } //----- write destination pixel *pipe->destColorPtr++ = cResult2; *pipe->destColorPtr++ = cResult1; *pipe->destColorPtr++ = cResult0; *pipe->destAlphaPtr++ = aResult; ++pipe->x; } #if SPLASH_CMYK // special case: // !pipe->pattern && !pipe->noTransparency && !state->softMask && // pipe->usesShape && !pipe->alpha0Ptr && !state->blendFunc && // !pipe->nonIsolatedGroup && // bitmap->mode == splashModeCMYK8 && pipe->destAlphaPtr void Splash::pipeRunAACMYK8(SplashPipe *pipe) { Guchar aSrc, aDest, alpha2, aResult; SplashColor cDest; Guchar cResult0, cResult1, cResult2, cResult3; //----- read destination pixel cDest[0] = pipe->destColorPtr[0]; cDest[1] = pipe->destColorPtr[1]; cDest[2] = pipe->destColorPtr[2]; cDest[3] = pipe->destColorPtr[3]; aDest = *pipe->destAlphaPtr; //----- source alpha aSrc = div255(pipe->aInput * pipe->shape); //----- result alpha and non-isolated group element correction aResult = aSrc + aDest - div255(aSrc * aDest); alpha2 = aResult; //----- result color if (alpha2 == 0) { cResult0 = 0; cResult1 = 0; cResult2 = 0; cResult3 = 0; } else { cResult0 = state->cmykTransferC[(Guchar)(((alpha2 - aSrc) * cDest[0] + aSrc * pipe->cSrc[0]) / alpha2)]; cResult1 = state->cmykTransferM[(Guchar)(((alpha2 - aSrc) * cDest[1] + aSrc * pipe->cSrc[1]) / alpha2)]; cResult2 = state->cmykTransferY[(Guchar)(((alpha2 - aSrc) * cDest[2] + aSrc * pipe->cSrc[2]) / alpha2)]; cResult3 = state->cmykTransferK[(Guchar)(((alpha2 - aSrc) * cDest[3] + aSrc * pipe->cSrc[3]) / alpha2)]; } //----- write destination pixel if (state->overprintMask & 1) { pipe->destColorPtr[0] = cResult0; } if (state->overprintMask & 2) { pipe->destColorPtr[1] = cResult1; } if (state->overprintMask & 4) { pipe->destColorPtr[2] = cResult2; } if (state->overprintMask & 8) { pipe->destColorPtr[3] = cResult3; } pipe->destColorPtr += 4; *pipe->destAlphaPtr++ = aResult; ++pipe->x; } #endif inline void Splash::pipeSetXY(SplashPipe *pipe, int x, int y) { pipe->x = x; pipe->y = y; if (state->softMask) { pipe->softMaskPtr = &state->softMask->data[y * state->softMask->rowSize + x]; } switch (bitmap->mode) { case splashModeMono1: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + (x >> 3)]; pipe->destColorMask = 0x80 >> (x & 7); break; case splashModeMono8: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + x]; break; case splashModeRGB8: case splashModeBGR8: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 3 * x]; break; #if SPLASH_CMYK case splashModeCMYK8: pipe->destColorPtr = &bitmap->data[y * bitmap->rowSize + 4 * x]; break; #endif } if (bitmap->alpha) { pipe->destAlphaPtr = &bitmap->alpha[y * bitmap->width + x]; } else { pipe->destAlphaPtr = NULL; } if (state->inNonIsolatedGroup && alpha0Bitmap->alpha) { pipe->alpha0Ptr = &alpha0Bitmap->alpha[(alpha0Y + y) * alpha0Bitmap->width + (alpha0X + x)]; } else { pipe->alpha0Ptr = NULL; } } inline void Splash::pipeIncX(SplashPipe *pipe) { ++pipe->x; if (state->softMask) { ++pipe->softMaskPtr; } switch (bitmap->mode) { case splashModeMono1: if (!(pipe->destColorMask >>= 1)) { pipe->destColorMask = 0x80; ++pipe->destColorPtr; } break; case splashModeMono8: ++pipe->destColorPtr; break; case splashModeRGB8: case splashModeBGR8: pipe->destColorPtr += 3; break; #if SPLASH_CMYK case splashModeCMYK8: pipe->destColorPtr += 4; break; #endif } if (pipe->destAlphaPtr) { ++pipe->destAlphaPtr; } if (pipe->alpha0Ptr) { ++pipe->alpha0Ptr; } } inline void Splash::drawPixel(SplashPipe *pipe, int x, int y, GBool noClip) { if (noClip || state->clip->test(x, y)) { pipeSetXY(pipe, x, y); (this->*pipe->run)(pipe); updateModX(x); updateModY(y); } } inline void Splash::drawAAPixelInit() { aaBufY = -1; } inline void Splash::drawAAPixel(SplashPipe *pipe, int x, int y) { #if splashAASize == 4 static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; int w; #else int xx, yy; #endif SplashColorPtr p; int x0, x1, t; if (x < 0 || x >= bitmap->width || y < state->clip->getYMinI() || y > state->clip->getYMaxI()) { return; } // update aaBuf if (y != aaBufY) { memset(aaBuf->getDataPtr(), 0xff, aaBuf->getRowSize() * aaBuf->getHeight()); x0 = 0; x1 = bitmap->width - 1; state->clip->clipAALine(aaBuf, &x0, &x1, y); aaBufY = y; } // compute the shape value #if splashAASize == 4 p = aaBuf->getDataPtr() + (x >> 1); w = aaBuf->getRowSize(); if (x & 1) { t = bitCount4[*p & 0x0f] + bitCount4[p[w] & 0x0f] + bitCount4[p[2*w] & 0x0f] + bitCount4[p[3*w] & 0x0f]; } else { t = bitCount4[*p >> 4] + bitCount4[p[w] >> 4] + bitCount4[p[2*w] >> 4] + bitCount4[p[3*w] >> 4]; } #else t = 0; for (yy = 0; yy < splashAASize; ++yy) { for (xx = 0; xx < splashAASize; ++xx) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + ((x * splashAASize + xx) >> 3); t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; } } #endif // draw the pixel if (t != 0) { pipeSetXY(pipe, x, y); pipe->shape = div255(aaGamma[t] * pipe->shape); (this->*pipe->run)(pipe); updateModX(x); updateModY(y); } } inline void Splash::drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip) { int x; if (noClip) { pipeSetXY(pipe, x0, y); for (x = x0; x <= x1; ++x) { (this->*pipe->run)(pipe); } updateModX(x0); updateModX(x1); updateModY(y); } else { if (x0 < state->clip->getXMinI()) { x0 = state->clip->getXMinI(); } if (x1 > state->clip->getXMaxI()) { x1 = state->clip->getXMaxI(); } pipeSetXY(pipe, x0, y); for (x = x0; x <= x1; ++x) { if (state->clip->test(x, y)) { (this->*pipe->run)(pipe); updateModX(x); updateModY(y); } else { pipeIncX(pipe); } } } } inline void Splash::drawAALine(SplashPipe *pipe, int x0, int x1, int y) { #if splashAASize == 4 static int bitCount4[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; SplashColorPtr p0, p1, p2, p3; int t; #else SplashColorPtr p; int xx, yy, t; #endif int x; #if splashAASize == 4 p0 = aaBuf->getDataPtr() + (x0 >> 1); p1 = p0 + aaBuf->getRowSize(); p2 = p1 + aaBuf->getRowSize(); p3 = p2 + aaBuf->getRowSize(); #endif pipeSetXY(pipe, x0, y); for (x = x0; x <= x1; ++x) { // compute the shape value #if splashAASize == 4 if (x & 1) { t = bitCount4[*p0 & 0x0f] + bitCount4[*p1 & 0x0f] + bitCount4[*p2 & 0x0f] + bitCount4[*p3 & 0x0f]; ++p0; ++p1; ++p2; ++p3; } else { t = bitCount4[*p0 >> 4] + bitCount4[*p1 >> 4] + bitCount4[*p2 >> 4] + bitCount4[*p3 >> 4]; } #else t = 0; for (yy = 0; yy < splashAASize; ++yy) { for (xx = 0; xx < splashAASize; ++xx) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + ((x * splashAASize + xx) >> 3); t += (*p >> (7 - ((x * splashAASize + xx) & 7))) & 1; } } #endif if (t != 0) { pipe->shape = aaGamma[t]; (this->*pipe->run)(pipe); updateModX(x); updateModY(y); } else { pipeIncX(pipe); } } } //------------------------------------------------------------------------ // Transform a point from user space to device space. inline void Splash::transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo) { // [ m[0] m[1] 0 ] // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] // [ m[4] m[5] 1 ] *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; } //------------------------------------------------------------------------ // Splash //------------------------------------------------------------------------ Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreenParams *screenParams) { int i; bitmap = bitmapA; vectorAntialias = vectorAntialiasA; inShading = gFalse; state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenParams); if (vectorAntialias) { aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, 1, splashModeMono1, gFalse); for (i = 0; i <= splashAASize * splashAASize; ++i) { aaGamma[i] = (Guchar)splashRound( splashPow((SplashCoord)i / (SplashCoord)(splashAASize * splashAASize), splashAAGamma) * 255); } } else { aaBuf = NULL; } minLineWidth = 0; clearModRegion(); debugMode = gFalse; } Splash::Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreen *screenA) { int i; bitmap = bitmapA; vectorAntialias = vectorAntialiasA; inShading = gFalse; state = new SplashState(bitmap->width, bitmap->height, vectorAntialias, screenA); if (vectorAntialias) { aaBuf = new SplashBitmap(splashAASize * bitmap->width, splashAASize, 1, splashModeMono1, gFalse); for (i = 0; i <= splashAASize * splashAASize; ++i) { aaGamma[i] = (Guchar)splashRound( splashPow((SplashCoord)i / (SplashCoord)(splashAASize * splashAASize), splashAAGamma) * 255); } } else { aaBuf = NULL; } minLineWidth = 0; clearModRegion(); debugMode = gFalse; } Splash::~Splash() { while (state->next) { restoreState(); } delete state; if (vectorAntialias) { delete aaBuf; } } //------------------------------------------------------------------------ // state read //------------------------------------------------------------------------ SplashCoord *Splash::getMatrix() { return state->matrix; } SplashPattern *Splash::getStrokePattern() { return state->strokePattern; } SplashPattern *Splash::getFillPattern() { return state->fillPattern; } SplashScreen *Splash::getScreen() { return state->screen; } SplashBlendFunc Splash::getBlendFunc() { return state->blendFunc; } SplashCoord Splash::getStrokeAlpha() { return state->strokeAlpha; } SplashCoord Splash::getFillAlpha() { return state->fillAlpha; } SplashCoord Splash::getLineWidth() { return state->lineWidth; } int Splash::getLineCap() { return state->lineCap; } int Splash::getLineJoin() { return state->lineJoin; } SplashCoord Splash::getMiterLimit() { return state->miterLimit; } SplashCoord Splash::getFlatness() { return state->flatness; } SplashCoord *Splash::getLineDash() { return state->lineDash; } int Splash::getLineDashLength() { return state->lineDashLength; } SplashCoord Splash::getLineDashPhase() { return state->lineDashPhase; } GBool Splash::getStrokeAdjust() { return state->strokeAdjust; } SplashClip *Splash::getClip() { return state->clip; } SplashBitmap *Splash::getSoftMask() { return state->softMask; } GBool Splash::getInNonIsolatedGroup() { return state->inNonIsolatedGroup; } //------------------------------------------------------------------------ // state write //------------------------------------------------------------------------ void Splash::setMatrix(SplashCoord *matrix) { memcpy(state->matrix, matrix, 6 * sizeof(SplashCoord)); } void Splash::setStrokePattern(SplashPattern *strokePattern) { state->setStrokePattern(strokePattern); } void Splash::setFillPattern(SplashPattern *fillPattern) { state->setFillPattern(fillPattern); } void Splash::setScreen(SplashScreen *screen) { state->setScreen(screen); } void Splash::setBlendFunc(SplashBlendFunc func) { state->blendFunc = func; } void Splash::setStrokeAlpha(SplashCoord alpha) { state->strokeAlpha = alpha; } void Splash::setFillAlpha(SplashCoord alpha) { state->fillAlpha = alpha; } void Splash::setLineWidth(SplashCoord lineWidth) { state->lineWidth = lineWidth; } void Splash::setLineCap(int lineCap) { state->lineCap = lineCap; } void Splash::setLineJoin(int lineJoin) { state->lineJoin = lineJoin; } void Splash::setMiterLimit(SplashCoord miterLimit) { state->miterLimit = miterLimit; } void Splash::setFlatness(SplashCoord flatness) { if (flatness < 1) { state->flatness = 1; } else { state->flatness = flatness; } } void Splash::setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase) { state->setLineDash(lineDash, lineDashLength, lineDashPhase); } void Splash::setStrokeAdjust(GBool strokeAdjust) { state->strokeAdjust = strokeAdjust; } void Splash::clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { state->clip->resetToRect(x0, y0, x1, y1); } SplashError Splash::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { return state->clip->clipToRect(x0, y0, x1, y1); } SplashError Splash::clipToPath(SplashPath *path, GBool eo) { return state->clip->clipToPath(path, state->matrix, state->flatness, eo); } void Splash::setSoftMask(SplashBitmap *softMask) { state->setSoftMask(softMask); } void Splash::setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, int alpha0XA, int alpha0YA) { alpha0Bitmap = alpha0BitmapA; alpha0X = alpha0XA; alpha0Y = alpha0YA; state->inNonIsolatedGroup = gTrue; } void Splash::setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray) { state->setTransfer(red, green, blue, gray); } void Splash::setOverprintMask(Guint overprintMask) { state->overprintMask = overprintMask; } //------------------------------------------------------------------------ // state save/restore //------------------------------------------------------------------------ void Splash::saveState() { SplashState *newState; newState = state->copy(); newState->next = state; state = newState; } SplashError Splash::restoreState() { SplashState *oldState; if (!state->next) { return splashErrNoSave; } oldState = state; state = state->next; delete oldState; return splashOk; } //------------------------------------------------------------------------ // drawing operations //------------------------------------------------------------------------ void Splash::clear(SplashColorPtr color, Guchar alpha) { SplashColorPtr row, p; Guchar mono; int x, y; switch (bitmap->mode) { case splashModeMono1: mono = (color[0] & 0x80) ? 0xff : 0x00; if (bitmap->rowSize < 0) { memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), mono, -bitmap->rowSize * bitmap->height); } else { memset(bitmap->data, mono, bitmap->rowSize * bitmap->height); } break; case splashModeMono8: if (bitmap->rowSize < 0) { memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), color[0], -bitmap->rowSize * bitmap->height); } else { memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); } break; case splashModeRGB8: if (color[0] == color[1] && color[1] == color[2]) { if (bitmap->rowSize < 0) { memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), color[0], -bitmap->rowSize * bitmap->height); } else { memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); } } else { row = bitmap->data; for (y = 0; y < bitmap->height; ++y) { p = row; for (x = 0; x < bitmap->width; ++x) { *p++ = color[2]; *p++ = color[1]; *p++ = color[0]; } row += bitmap->rowSize; } } break; case splashModeBGR8: if (color[0] == color[1] && color[1] == color[2]) { if (bitmap->rowSize < 0) { memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), color[0], -bitmap->rowSize * bitmap->height); } else { memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); } } else { row = bitmap->data; for (y = 0; y < bitmap->height; ++y) { p = row; for (x = 0; x < bitmap->width; ++x) { *p++ = color[0]; *p++ = color[1]; *p++ = color[2]; } row += bitmap->rowSize; } } break; #if SPLASH_CMYK case splashModeCMYK8: if (color[0] == color[1] && color[1] == color[2] && color[2] == color[3]) { if (bitmap->rowSize < 0) { memset(bitmap->data + bitmap->rowSize * (bitmap->height - 1), color[0], -bitmap->rowSize * bitmap->height); } else { memset(bitmap->data, color[0], bitmap->rowSize * bitmap->height); } } else { row = bitmap->data; for (y = 0; y < bitmap->height; ++y) { p = row; for (x = 0; x < bitmap->width; ++x) { *p++ = color[0]; *p++ = color[1]; *p++ = color[2]; *p++ = color[3]; } row += bitmap->rowSize; } } break; #endif } if (bitmap->alpha) { memset(bitmap->alpha, alpha, bitmap->width * bitmap->height); } updateModX(0); updateModY(0); updateModX(bitmap->width - 1); updateModY(bitmap->height - 1); } SplashError Splash::stroke(SplashPath *path) { SplashPath *path2, *dPath; SplashCoord d1, d2, t1, t2, w; if (debugMode) { printf("stroke [dash:%d] [width:%.2f]:\n", state->lineDashLength, (double)state->lineWidth); dumpPath(path); } opClipRes = splashClipAllOutside; if (path->length == 0) { return splashErrEmptyPath; } path2 = flattenPath(path, state->matrix, state->flatness); if (state->lineDashLength > 0) { dPath = makeDashedPath(path2); delete path2; path2 = dPath; if (path2->length == 0) { delete path2; return splashErrEmptyPath; } } // transform a unit square, and take the half the max of the two // diagonals; the product of this number and the line width is the // (approximate) transformed line width t1 = state->matrix[0] + state->matrix[2]; t2 = state->matrix[1] + state->matrix[3]; d1 = t1 * t1 + t2 * t2; t1 = state->matrix[0] - state->matrix[2]; t2 = state->matrix[1] - state->matrix[3]; d2 = t1 * t1 + t2 * t2; if (d2 > d1) { d1 = d2; } d1 *= 0.5; if (d1 > 0 && d1 * state->lineWidth * state->lineWidth < minLineWidth * minLineWidth) { w = minLineWidth / splashSqrt(d1); strokeWide(path2, w); } else if (bitmap->mode == splashModeMono1) { // this gets close to Adobe's behavior in mono mode if (d1 <= 2) { strokeNarrow(path2); } else { strokeWide(path2, state->lineWidth); } } else { if (state->lineWidth == 0) { strokeNarrow(path2); } else { strokeWide(path2, state->lineWidth); } } delete path2; return splashOk; } void Splash::strokeNarrow(SplashPath *path) { SplashPipe pipe; SplashXPath *xPath; SplashXPathSeg *seg; int x0, x1, y0, y1, xa, xb, y; SplashCoord dxdy; SplashClipResult clipRes; int nClipRes[3]; int i; nClipRes[0] = nClipRes[1] = nClipRes[2] = 0; xPath = new SplashXPath(path, state->matrix, state->flatness, gFalse); pipeInit(&pipe, 0, 0, state->strokePattern, NULL, (Guchar)splashRound(state->strokeAlpha * 255), gFalse, gFalse); for (i = 0, seg = xPath->segs; i < xPath->length; ++i, ++seg) { if (seg->y0 <= seg->y1) { y0 = splashFloor(seg->y0); y1 = splashFloor(seg->y1); x0 = splashFloor(seg->x0); x1 = splashFloor(seg->x1); } else { y0 = splashFloor(seg->y1); y1 = splashFloor(seg->y0); x0 = splashFloor(seg->x1); x1 = splashFloor(seg->x0); } if ((clipRes = state->clip->testRect(x0 <= x1 ? x0 : x1, y0, x0 <= x1 ? x1 : x0, y1)) != splashClipAllOutside) { if (y0 == y1) { if (x0 <= x1) { drawSpan(&pipe, x0, x1, y0, clipRes == splashClipAllInside); } else { drawSpan(&pipe, x1, x0, y0, clipRes == splashClipAllInside); } } else { dxdy = seg->dxdy; if (y0 < state->clip->getYMinI()) { y0 = state->clip->getYMinI(); x0 = splashFloor(seg->x0 + ((SplashCoord)y0 - seg->y0) * dxdy); } if (y1 > state->clip->getYMaxI()) { y1 = state->clip->getYMaxI(); x1 = splashFloor(seg->x0 + ((SplashCoord)y1 - seg->y0) * dxdy); } if (x0 <= x1) { xa = x0; for (y = y0; y <= y1; ++y) { if (y < y1) { xb = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); } else { xb = x1 + 1; } if (xa == xb) { drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); } else { drawSpan(&pipe, xa, xb - 1, y, clipRes == splashClipAllInside); } xa = xb; } } else { xa = x0; for (y = y0; y <= y1; ++y) { if (y < y1) { xb = splashFloor(seg->x0 + ((SplashCoord)y + 1 - seg->y0) * dxdy); } else { xb = x1 - 1; } if (xa == xb) { drawPixel(&pipe, xa, y, clipRes == splashClipAllInside); } else { drawSpan(&pipe, xb + 1, xa, y, clipRes == splashClipAllInside); } xa = xb; } } } } ++nClipRes[clipRes]; } if (nClipRes[splashClipPartial] || (nClipRes[splashClipAllInside] && nClipRes[splashClipAllOutside])) { opClipRes = splashClipPartial; } else if (nClipRes[splashClipAllInside]) { opClipRes = splashClipAllInside; } else { opClipRes = splashClipAllOutside; } delete xPath; } void Splash::strokeWide(SplashPath *path, SplashCoord w) { SplashPath *path2; path2 = makeStrokePath(path, w, gFalse); fillWithPattern(path2, gFalse, state->strokePattern, state->strokeAlpha); delete path2; } SplashPath *Splash::flattenPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness) { SplashPath *fPath; SplashCoord flatness2; Guchar flag; int i; fPath = new SplashPath(); #if USE_FIXEDPOINT flatness2 = flatness; #else flatness2 = flatness * flatness; #endif i = 0; while (i < path->length) { flag = path->flags[i]; if (flag & splashPathFirst) { fPath->moveTo(path->pts[i].x, path->pts[i].y); ++i; } else { if (flag & splashPathCurve) { flattenCurve(path->pts[i-1].x, path->pts[i-1].y, path->pts[i ].x, path->pts[i ].y, path->pts[i+1].x, path->pts[i+1].y, path->pts[i+2].x, path->pts[i+2].y, matrix, flatness2, fPath); i += 3; } else { fPath->lineTo(path->pts[i].x, path->pts[i].y); ++i; } if (path->flags[i-1] & splashPathClosed) { fPath->close(); } } } return fPath; } void Splash::flattenCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3, SplashCoord *matrix, SplashCoord flatness2, SplashPath *fPath) { SplashCoord cx[splashMaxCurveSplits + 1][3]; SplashCoord cy[splashMaxCurveSplits + 1][3]; int cNext[splashMaxCurveSplits + 1]; SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; SplashCoord dx, dy, mx, my, tx, ty, d1, d2; int p1, p2, p3; // initial segment p1 = 0; p2 = splashMaxCurveSplits; cx[p1][0] = x0; cy[p1][0] = y0; cx[p1][1] = x1; cy[p1][1] = y1; cx[p1][2] = x2; cy[p1][2] = y2; cx[p2][0] = x3; cy[p2][0] = y3; cNext[p1] = p2; while (p1 < splashMaxCurveSplits) { // get the next segment xl0 = cx[p1][0]; yl0 = cy[p1][0]; xx1 = cx[p1][1]; yy1 = cy[p1][1]; xx2 = cx[p1][2]; yy2 = cy[p1][2]; p2 = cNext[p1]; xr3 = cx[p2][0]; yr3 = cy[p2][0]; // compute the distances (in device space) from the control points // to the midpoint of the straight line (this is a bit of a hack, // but it's much faster than computing the actual distances to the // line) transform(matrix, (xl0 + xr3) * 0.5, (yl0 + yr3) * 0.5, &mx, &my); transform(matrix, xx1, yy1, &tx, &ty); #if USE_FIXEDPOINT d1 = splashDist(tx, ty, mx, my); #else dx = tx - mx; dy = ty - my; d1 = dx*dx + dy*dy; #endif transform(matrix, xx2, yy2, &tx, &ty); #if USE_FIXEDPOINT d2 = splashDist(tx, ty, mx, my); #else dx = tx - mx; dy = ty - my; d2 = dx*dx + dy*dy; #endif // if the curve is flat enough, or no more subdivisions are // allowed, add the straight line segment if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { fPath->lineTo(xr3, yr3); p1 = p2; // otherwise, subdivide the curve } else { xl1 = splashAvg(xl0, xx1); yl1 = splashAvg(yl0, yy1); xh = splashAvg(xx1, xx2); yh = splashAvg(yy1, yy2); xl2 = splashAvg(xl1, xh); yl2 = splashAvg(yl1, yh); xr2 = splashAvg(xx2, xr3); yr2 = splashAvg(yy2, yr3); xr1 = splashAvg(xh, xr2); yr1 = splashAvg(yh, yr2); xr0 = splashAvg(xl2, xr1); yr0 = splashAvg(yl2, yr1); // add the new subdivision points p3 = (p1 + p2) / 2; cx[p1][1] = xl1; cy[p1][1] = yl1; cx[p1][2] = xl2; cy[p1][2] = yl2; cNext[p1] = p3; cx[p3][0] = xr0; cy[p3][0] = yr0; cx[p3][1] = xr1; cy[p3][1] = yr1; cx[p3][2] = xr2; cy[p3][2] = yr2; cNext[p3] = p2; } } } SplashPath *Splash::makeDashedPath(SplashPath *path) { SplashPath *dPath; SplashCoord lineDashTotal; SplashCoord lineDashStartPhase, lineDashDist, segLen; SplashCoord x0, y0, x1, y1, xa, ya; GBool lineDashStartOn, lineDashOn, newPath; int lineDashStartIdx, lineDashIdx; int i, j, k; lineDashTotal = 0; for (i = 0; i < state->lineDashLength; ++i) { lineDashTotal += state->lineDash[i]; } // Acrobat simply draws nothing if the dash array is [0] if (lineDashTotal == 0) { return new SplashPath(); } lineDashStartPhase = state->lineDashPhase; i = splashFloor(lineDashStartPhase / lineDashTotal); lineDashStartPhase -= (SplashCoord)i * lineDashTotal; lineDashStartOn = gTrue; lineDashStartIdx = 0; if (lineDashStartPhase > 0) { while (lineDashStartPhase >= state->lineDash[lineDashStartIdx]) { lineDashStartOn = !lineDashStartOn; lineDashStartPhase -= state->lineDash[lineDashStartIdx]; ++lineDashStartIdx; } } dPath = new SplashPath(); // process each subpath i = 0; while (i < path->length) { // find the end of the subpath for (j = i; j < path->length - 1 && !(path->flags[j] & splashPathLast); ++j) ; // initialize the dash parameters lineDashOn = lineDashStartOn; lineDashIdx = lineDashStartIdx; lineDashDist = state->lineDash[lineDashIdx] - lineDashStartPhase; // process each segment of the subpath newPath = gTrue; for (k = i; k < j; ++k) { // grab the segment x0 = path->pts[k].x; y0 = path->pts[k].y; x1 = path->pts[k+1].x; y1 = path->pts[k+1].y; segLen = splashDist(x0, y0, x1, y1); // process the segment while (segLen > 0) { if (lineDashDist >= segLen) { if (lineDashOn) { if (newPath) { dPath->moveTo(x0, y0); newPath = gFalse; } dPath->lineTo(x1, y1); } lineDashDist -= segLen; segLen = 0; } else { xa = x0 + (lineDashDist / segLen) * (x1 - x0); ya = y0 + (lineDashDist / segLen) * (y1 - y0); if (lineDashOn) { if (newPath) { dPath->moveTo(x0, y0); newPath = gFalse; } dPath->lineTo(xa, ya); } x0 = xa; y0 = ya; segLen -= lineDashDist; lineDashDist = 0; } // get the next entry in the dash array if (lineDashDist <= 0) { lineDashOn = !lineDashOn; if (++lineDashIdx == state->lineDashLength) { lineDashIdx = 0; } lineDashDist = state->lineDash[lineDashIdx]; newPath = gTrue; } } } i = j + 1; } return dPath; } SplashError Splash::fill(SplashPath *path, GBool eo) { if (debugMode) { printf("fill [eo:%d]:\n", eo); dumpPath(path); } return fillWithPattern(path, eo, state->fillPattern, state->fillAlpha); } SplashError Splash::fillWithPattern(SplashPath *path, GBool eo, SplashPattern *pattern, SplashCoord alpha) { SplashPipe pipe; SplashXPath *xPath; SplashXPathScanner *scanner; int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; SplashClipResult clipRes, clipRes2; if (path->length == 0) { return splashErrEmptyPath; } if (pathAllOutside(path)) { opClipRes = splashClipAllOutside; return splashOk; } // add stroke adjustment hints for filled rectangles -- this only // applies to paths that consist of a single subpath // (this appears to match Acrobat's behavior) if (state->strokeAdjust && !path->hints) { int n; n = path->getLength(); if (n == 4 && !(path->flags[0] & splashPathClosed) && !(path->flags[1] & splashPathLast) && !(path->flags[2] & splashPathLast)) { path->close(gTrue); path->addStrokeAdjustHint(0, 2, 0, 4); path->addStrokeAdjustHint(1, 3, 0, 4); } else if (n == 5 && (path->flags[0] & splashPathClosed) && !(path->flags[1] & splashPathLast) && !(path->flags[2] & splashPathLast) && !(path->flags[3] & splashPathLast)) { path->addStrokeAdjustHint(0, 2, 0, 4); path->addStrokeAdjustHint(1, 3, 0, 4); } } xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); if (vectorAntialias && !inShading) { xPath->aaScale(); } xPath->sort(); yMinI = state->clip->getYMinI(); yMaxI = state->clip->getYMaxI(); if (vectorAntialias && !inShading) { yMinI = yMinI * splashAASize; yMaxI = (yMaxI + 1) * splashAASize - 1; } scanner = new SplashXPathScanner(xPath, eo, yMinI, yMaxI); // get the min and max x and y values if (vectorAntialias && !inShading) { scanner->getBBoxAA(&xMinI, &yMinI, &xMaxI, &yMaxI); } else { scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); } // check clipping if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { if (scanner->hasPartialClip()) { clipRes = splashClipPartial; } pipeInit(&pipe, 0, yMinI, pattern, NULL, (Guchar)splashRound(alpha * 255), vectorAntialias && !inShading, gFalse); // draw the spans if (vectorAntialias && !inShading) { for (y = yMinI; y <= yMaxI; ++y) { scanner->renderAALine(aaBuf, &x0, &x1, y); if (clipRes != splashClipAllInside) { state->clip->clipAALine(aaBuf, &x0, &x1, y); } drawAALine(&pipe, x0, x1, y); } } else { for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(&pipe, x0, x1, y, gTrue); } else { // limit the x range if (x0 < state->clip->getXMinI()) { x0 = state->clip->getXMinI(); } if (x1 > state->clip->getXMaxI()) { x1 = state->clip->getXMaxI(); } clipRes2 = state->clip->testSpan(x0, x1, y); drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); } } } } } opClipRes = clipRes; delete scanner; delete xPath; return splashOk; } GBool Splash::pathAllOutside(SplashPath *path) { SplashCoord xMin1, yMin1, xMax1, yMax1; SplashCoord xMin2, yMin2, xMax2, yMax2; SplashCoord x, y; int xMinI, yMinI, xMaxI, yMaxI; int i; xMin1 = xMax1 = path->pts[0].x; yMin1 = yMax1 = path->pts[0].y; for (i = 1; i < path->length; ++i) { if (path->pts[i].x < xMin1) { xMin1 = path->pts[i].x; } else if (path->pts[i].x > xMax1) { xMax1 = path->pts[i].x; } if (path->pts[i].y < yMin1) { yMin1 = path->pts[i].y; } else if (path->pts[i].y > yMax1) { yMax1 = path->pts[i].y; } } transform(state->matrix, xMin1, yMin1, &x, &y); xMin2 = xMax2 = x; yMin2 = yMax2 = y; transform(state->matrix, xMin1, yMax1, &x, &y); if (x < xMin2) { xMin2 = x; } else if (x > xMax2) { xMax2 = x; } if (y < yMin2) { yMin2 = y; } else if (y > yMax2) { yMax2 = y; } transform(state->matrix, xMax1, yMin1, &x, &y); if (x < xMin2) { xMin2 = x; } else if (x > xMax2) { xMax2 = x; } if (y < yMin2) { yMin2 = y; } else if (y > yMax2) { yMax2 = y; } transform(state->matrix, xMax1, yMax1, &x, &y); if (x < xMin2) { xMin2 = x; } else if (x > xMax2) { xMax2 = x; } if (y < yMin2) { yMin2 = y; } else if (y > yMax2) { yMax2 = y; } xMinI = splashFloor(xMin2); yMinI = splashFloor(yMin2); xMaxI = splashFloor(xMax2); yMaxI = splashFloor(yMax2); return state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI) == splashClipAllOutside; } SplashError Splash::xorFill(SplashPath *path, GBool eo) { SplashPipe pipe; SplashXPath *xPath; SplashXPathScanner *scanner; int xMinI, yMinI, xMaxI, yMaxI, x0, x1, y; SplashClipResult clipRes, clipRes2; SplashBlendFunc origBlendFunc; if (path->length == 0) { return splashErrEmptyPath; } xPath = new SplashXPath(path, state->matrix, state->flatness, gTrue); xPath->sort(); scanner = new SplashXPathScanner(xPath, eo, state->clip->getYMinI(), state->clip->getYMaxI()); // get the min and max x and y values scanner->getBBox(&xMinI, &yMinI, &xMaxI, &yMaxI); // check clipping if ((clipRes = state->clip->testRect(xMinI, yMinI, xMaxI, yMaxI)) != splashClipAllOutside) { if (scanner->hasPartialClip()) { clipRes = splashClipPartial; } origBlendFunc = state->blendFunc; state->blendFunc = &blendXor; pipeInit(&pipe, 0, yMinI, state->fillPattern, NULL, 255, gFalse, gFalse); // draw the spans for (y = yMinI; y <= yMaxI; ++y) { while (scanner->getNextSpan(y, &x0, &x1)) { if (clipRes == splashClipAllInside) { drawSpan(&pipe, x0, x1, y, gTrue); } else { // limit the x range if (x0 < state->clip->getXMinI()) { x0 = state->clip->getXMinI(); } if (x1 > state->clip->getXMaxI()) { x1 = state->clip->getXMaxI(); } clipRes2 = state->clip->testSpan(x0, x1, y); drawSpan(&pipe, x0, x1, y, clipRes2 == splashClipAllInside); } } } state->blendFunc = origBlendFunc; } opClipRes = clipRes; delete scanner; delete xPath; return splashOk; } SplashError Splash::fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font) { SplashGlyphBitmap glyph; SplashCoord xt, yt; int x0, y0, xFrac, yFrac; SplashError err; if (debugMode) { printf("fillChar: x=%.2f y=%.2f c=%3d=0x%02x='%c'\n", (double)x, (double)y, c, c, c); } transform(state->matrix, x, y, &xt, &yt); x0 = splashFloor(xt); xFrac = splashFloor((xt - x0) * splashFontFraction); y0 = splashFloor(yt); yFrac = splashFloor((yt - y0) * splashFontFraction); if (!font->getGlyph(c, xFrac, yFrac, &glyph)) { return splashErrNoGlyph; } err = fillGlyph2(x0, y0, &glyph); if (glyph.freeData) { gfree(glyph.data); } return err; } SplashError Splash::fillGlyph(SplashCoord x, SplashCoord y, SplashGlyphBitmap *glyph) { SplashCoord xt, yt; int x0, y0; transform(state->matrix, x, y, &xt, &yt); x0 = splashFloor(xt); y0 = splashFloor(yt); return fillGlyph2(x0, y0, glyph); } SplashError Splash::fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph) { SplashPipe pipe; SplashClipResult clipRes; GBool noClip; int alpha0; Guchar alpha; Guchar *p; int x1, y1, xx, xx1, yy; if ((clipRes = state->clip->testRect(x0 - glyph->x, y0 - glyph->y, x0 - glyph->x + glyph->w - 1, y0 - glyph->y + glyph->h - 1)) != splashClipAllOutside) { noClip = clipRes == splashClipAllInside; if (noClip) { if (glyph->aa) { pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { pipeSetXY(&pipe, x0 - glyph->x, y1); for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { alpha = *p++; if (alpha != 0) { pipe.shape = alpha; (this->*pipe.run)(&pipe); updateModX(x1); updateModY(y1); } else { pipeIncX(&pipe); } } } } else { pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { pipeSetXY(&pipe, x0 - glyph->x, y1); for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { alpha0 = *p++; for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { if (alpha0 & 0x80) { (this->*pipe.run)(&pipe); updateModX(x1); updateModY(y1); } else { pipeIncX(&pipe); } alpha0 <<= 1; } } } } } else { if (glyph->aa) { pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { pipeSetXY(&pipe, x0 - glyph->x, y1); for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; ++xx, ++x1) { if (state->clip->test(x1, y1)) { alpha = *p++; if (alpha != 0) { pipe.shape = alpha; (this->*pipe.run)(&pipe); updateModX(x1); updateModY(y1); } else { pipeIncX(&pipe); } } else { pipeIncX(&pipe); ++p; } } } } else { pipeInit(&pipe, x0 - glyph->x, y0 - glyph->y, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gFalse, gFalse); p = glyph->data; for (yy = 0, y1 = y0 - glyph->y; yy < glyph->h; ++yy, ++y1) { pipeSetXY(&pipe, x0 - glyph->x, y1); for (xx = 0, x1 = x0 - glyph->x; xx < glyph->w; xx += 8) { alpha0 = *p++; for (xx1 = 0; xx1 < 8 && xx + xx1 < glyph->w; ++xx1, ++x1) { if (state->clip->test(x1, y1)) { if (alpha0 & 0x80) { (this->*pipe.run)(&pipe); updateModX(x1); updateModY(y1); } else { pipeIncX(&pipe); } } else { pipeIncX(&pipe); } alpha0 <<= 1; } } } } } } opClipRes = clipRes; return splashOk; } SplashError Splash::fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, GBool glyphMode) { SplashBitmap *scaledMask; SplashClipResult clipRes; GBool minorAxisZero; int x0, y0, x1, y1, scaledWidth, scaledHeight; if (debugMode) { printf("fillImageMask: w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", w, h, (double)mat[0], (double)mat[1], (double)mat[2], (double)mat[3], (double)mat[4], (double)mat[5]); } // check for singular matrix if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { return splashErrSingularMatrix; } minorAxisZero = mat[1] == 0 && mat[2] == 0; // scaling only if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { x0 = imgCoordMungeLowerC(mat[4], glyphMode); y0 = imgCoordMungeLowerC(mat[5], glyphMode); x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); y1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode); // make sure narrow images cover at least one pixel if (x0 == x1) { ++x1; } if (y0 == y1) { ++y1; } clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); opClipRes = clipRes; if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); blitMask(scaledMask, x0, y0, clipRes); delete scaledMask; } // scaling plus vertical flip } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { x0 = imgCoordMungeLowerC(mat[4], glyphMode); y0 = imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); x1 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode); y1 = imgCoordMungeUpperC(mat[5], glyphMode); // make sure narrow images cover at least one pixel if (x0 == x1) { ++x1; } if (y0 == y1) { ++y1; } clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); opClipRes = clipRes; if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; scaledMask = scaleMask(src, srcData, w, h, scaledWidth, scaledHeight); vertFlipImage(scaledMask, scaledWidth, scaledHeight, 1); blitMask(scaledMask, x0, y0, clipRes); delete scaledMask; } // all other cases } else { arbitraryTransformMask(src, srcData, w, h, mat, glyphMode); } return splashOk; } void Splash::arbitraryTransformMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, GBool glyphMode) { SplashBitmap *scaledMask; SplashClipResult clipRes, clipRes2; SplashPipe pipe; int scaledWidth, scaledHeight, t0, t1; SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; SplashCoord vx[4], vy[4]; int xMin, yMin, xMax, yMax; ImageSection section[3]; int nSections; int y, xa, xb, x, i, xx, yy; // compute the four vertices of the target quadrilateral vx[0] = mat[4]; vy[0] = mat[5]; vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; // clipping xMin = imgCoordMungeLowerC(vx[0], glyphMode); xMax = imgCoordMungeUpperC(vx[0], glyphMode); yMin = imgCoordMungeLowerC(vy[0], glyphMode); yMax = imgCoordMungeUpperC(vy[0], glyphMode); for (i = 1; i < 4; ++i) { t0 = imgCoordMungeLowerC(vx[i], glyphMode); if (t0 < xMin) { xMin = t0; } t0 = imgCoordMungeUpperC(vx[i], glyphMode); if (t0 > xMax) { xMax = t0; } t1 = imgCoordMungeLowerC(vy[i], glyphMode); if (t1 < yMin) { yMin = t1; } t1 = imgCoordMungeUpperC(vy[i], glyphMode); if (t1 > yMax) { yMax = t1; } } clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1); opClipRes = clipRes; if (clipRes == splashClipAllOutside) { return; } // compute the scale factors if (mat[0] >= 0) { t0 = imgCoordMungeUpperC(mat[0] + mat[4], glyphMode) - imgCoordMungeLowerC(mat[4], glyphMode); } else { t0 = imgCoordMungeUpperC(mat[4], glyphMode) - imgCoordMungeLowerC(mat[0] + mat[4], glyphMode); } if (mat[1] >= 0) { t1 = imgCoordMungeUpperC(mat[1] + mat[5], glyphMode) - imgCoordMungeLowerC(mat[5], glyphMode); } else { t1 = imgCoordMungeUpperC(mat[5], glyphMode) - imgCoordMungeLowerC(mat[1] + mat[5], glyphMode); } scaledWidth = t0 > t1 ? t0 : t1; if (mat[2] >= 0) { t0 = imgCoordMungeUpperC(mat[2] + mat[4], glyphMode) - imgCoordMungeLowerC(mat[4], glyphMode); } else { t0 = imgCoordMungeUpperC(mat[4], glyphMode) - imgCoordMungeLowerC(mat[2] + mat[4], glyphMode); } if (mat[3] >= 0) { t1 = imgCoordMungeUpperC(mat[3] + mat[5], glyphMode) - imgCoordMungeLowerC(mat[5], glyphMode); } else { t1 = imgCoordMungeUpperC(mat[5], glyphMode) - imgCoordMungeLowerC(mat[3] + mat[5], glyphMode); } scaledHeight = t0 > t1 ? t0 : t1; if (scaledWidth == 0) { scaledWidth = 1; } if (scaledHeight == 0) { scaledHeight = 1; } // compute the inverse transform (after scaling) matrix r00 = mat[0] / scaledWidth; r01 = mat[1] / scaledWidth; r10 = mat[2] / scaledHeight; r11 = mat[3] / scaledHeight; det = r00 * r11 - r01 * r10; if (splashAbs(det) < 1e-6) { // this should be caught by the singular matrix check in fillImageMask return; } ir00 = r11 / det; ir01 = -r01 / det; ir10 = -r10 / det; ir11 = r00 / det; // scale the input image scaledMask = scaleMask(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight); // construct the three sections i = (vy[2] <= vy[3]) ? 2 : 3; if (vy[1] <= vy[i]) { i = 1; } if (vy[0] < vy[i] || (i != 3 && vy[0] == vy[i])) { i = 0; } if (vy[i] == vy[(i+1) & 3]) { section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); section[0].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; if (vx[i] < vx[(i+1) & 3]) { section[0].ia0 = i; section[0].ia1 = (i+3) & 3; section[0].ib0 = (i+1) & 3; section[0].ib1 = (i+2) & 3; } else { section[0].ia0 = (i+1) & 3; section[0].ia1 = (i+2) & 3; section[0].ib0 = i; section[0].ib1 = (i+3) & 3; } nSections = 1; } else { section[0].y0 = imgCoordMungeLowerC(vy[i], glyphMode); section[2].y1 = imgCoordMungeUpperC(vy[(i+2) & 3], glyphMode) - 1; section[0].ia0 = section[0].ib0 = i; section[2].ia1 = section[2].ib1 = (i+2) & 3; if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[0].ia1 = section[2].ia0 = (i+1) & 3; section[0].ib1 = section[2].ib0 = (i+3) & 3; } else { section[0].ia1 = section[2].ia0 = (i+3) & 3; section[0].ib1 = section[2].ib0 = (i+1) & 3; } if (vy[(i+1) & 3] < vy[(i+3) & 3]) { section[1].y0 = imgCoordMungeLowerC(vy[(i+1) & 3], glyphMode); section[2].y0 = imgCoordMungeUpperC(vy[(i+3) & 3], glyphMode); if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[1].ia0 = (i+1) & 3; section[1].ia1 = (i+2) & 3; section[1].ib0 = i; section[1].ib1 = (i+3) & 3; } else { section[1].ia0 = i; section[1].ia1 = (i+3) & 3; section[1].ib0 = (i+1) & 3; section[1].ib1 = (i+2) & 3; } } else { section[1].y0 = imgCoordMungeLowerC(vy[(i+3) & 3], glyphMode); section[2].y0 = imgCoordMungeUpperC(vy[(i+1) & 3], glyphMode); if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[1].ia0 = i; section[1].ia1 = (i+1) & 3; section[1].ib0 = (i+3) & 3; section[1].ib1 = (i+2) & 3; } else { section[1].ia0 = (i+3) & 3; section[1].ia1 = (i+2) & 3; section[1].ib0 = i; section[1].ib1 = (i+1) & 3; } } section[0].y1 = section[1].y0 - 1; section[1].y1 = section[2].y0 - 1; nSections = 3; } for (i = 0; i < nSections; ++i) { section[i].xa0 = vx[section[i].ia0]; section[i].ya0 = vy[section[i].ia0]; section[i].xa1 = vx[section[i].ia1]; section[i].ya1 = vy[section[i].ia1]; section[i].xb0 = vx[section[i].ib0]; section[i].yb0 = vy[section[i].ib0]; section[i].xb1 = vx[section[i].ib1]; section[i].yb1 = vy[section[i].ib1]; section[i].dxdya = (section[i].xa1 - section[i].xa0) / (section[i].ya1 - section[i].ya0); section[i].dxdyb = (section[i].xb1 - section[i].xb0) / (section[i].yb1 - section[i].yb0); } // initialize the pixel pipe pipeInit(&pipe, 0, 0, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); if (vectorAntialias) { drawAAPixelInit(); } // make sure narrow images cover at least one pixel if (nSections == 1) { if (section[0].y0 == section[0].y1) { ++section[0].y1; clipRes = opClipRes = splashClipPartial; } } else { if (section[0].y0 == section[2].y1) { ++section[1].y1; clipRes = opClipRes = splashClipPartial; } } // scan all pixels inside the target region for (i = 0; i < nSections; ++i) { for (y = section[i].y0; y <= section[i].y1; ++y) { xa = imgCoordMungeLowerC(section[i].xa0 + ((SplashCoord)y + 0.5 - section[i].ya0) * section[i].dxdya, glyphMode); xb = imgCoordMungeUpperC(section[i].xb0 + ((SplashCoord)y + 0.5 - section[i].yb0) * section[i].dxdyb, glyphMode); // make sure narrow images cover at least one pixel if (xa == xb) { ++xb; } if (clipRes != splashClipAllInside) { clipRes2 = state->clip->testSpan(xa, xb - 1, y); } else { clipRes2 = clipRes; } for (x = xa; x < xb; ++x) { // map (x+0.5, y+0.5) back to the scaled image xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + ((SplashCoord)y + 0.5 - mat[5]) * ir10); yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + ((SplashCoord)y + 0.5 - mat[5]) * ir11); // xx should always be within bounds, but floating point // inaccuracy can cause problems if (xx < 0) { xx = 0; } else if (xx >= scaledWidth) { xx = scaledWidth - 1; } if (yy < 0) { yy = 0; } else if (yy >= scaledHeight) { yy = scaledHeight - 1; } pipe.shape = scaledMask->data[yy * scaledWidth + xx]; if (vectorAntialias && clipRes2 != splashClipAllInside) { drawAAPixel(&pipe, x, y); } else { drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); } } } } delete scaledMask; } // Scale an image mask into a SplashBitmap. SplashBitmap *Splash::scaleMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight) { SplashBitmap *dest; dest = new SplashBitmap(scaledWidth, scaledHeight, 1, splashModeMono8, gFalse); if (scaledHeight < srcHeight) { if (scaledWidth < srcWidth) { scaleMaskYdXd(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } else { scaleMaskYdXu(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } } else { if (scaledWidth < srcWidth) { scaleMaskYuXd(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } else { scaleMaskYuXu(src, srcData, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } } return dest; } void Splash::scaleMaskYdXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf; Guint *pixBuf; Guint pix; Guchar *destPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; int i, j; // Bresenham parameters for y scale yp = srcHeight / scaledHeight; yq = srcHeight % scaledHeight; // Bresenham parameters for x scale xp = srcWidth / scaledWidth; xq = srcWidth % scaledWidth; // allocate buffers lineBuf = (Guchar *)gmalloc(srcWidth); pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); // init y scale Bresenham yt = 0; destPtr = dest->data; for (y = 0; y < scaledHeight; ++y) { // y scale Bresenham if ((yt += yq) >= scaledHeight) { yt -= scaledHeight; yStep = yp + 1; } else { yStep = yp; } // read rows from image memset(pixBuf, 0, srcWidth * sizeof(int)); for (i = 0; i < yStep; ++i) { (*src)(srcData, lineBuf); for (j = 0; j < srcWidth; ++j) { pixBuf[j] += lineBuf[j]; } } // init x scale Bresenham xt = 0; d0 = (255 << 23) / (yStep * xp); d1 = (255 << 23) / (yStep * (xp + 1)); xx = 0; for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham if ((xt += xq) >= scaledWidth) { xt -= scaledWidth; xStep = xp + 1; d = d1; } else { xStep = xp; d = d0; } // compute the final pixel pix = 0; for (i = 0; i < xStep; ++i) { pix += pixBuf[xx++]; } // (255 * pix) / xStep * yStep pix = (pix * d) >> 23; // store the pixel *destPtr++ = (Guchar)pix; } } gfree(pixBuf); gfree(lineBuf); } void Splash::scaleMaskYdXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf; Guint *pixBuf; Guint pix; Guchar *destPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; int i, j; // Bresenham parameters for y scale yp = srcHeight / scaledHeight; yq = srcHeight % scaledHeight; // Bresenham parameters for x scale xp = scaledWidth / srcWidth; xq = scaledWidth % srcWidth; // allocate buffers lineBuf = (Guchar *)gmalloc(srcWidth); pixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); // init y scale Bresenham yt = 0; destPtr = dest->data; for (y = 0; y < scaledHeight; ++y) { // y scale Bresenham if ((yt += yq) >= scaledHeight) { yt -= scaledHeight; yStep = yp + 1; } else { yStep = yp; } // read rows from image memset(pixBuf, 0, srcWidth * sizeof(int)); for (i = 0; i < yStep; ++i) { (*src)(srcData, lineBuf); for (j = 0; j < srcWidth; ++j) { pixBuf[j] += lineBuf[j]; } } // init x scale Bresenham xt = 0; d = (255 << 23) / yStep; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham if ((xt += xq) >= srcWidth) { xt -= srcWidth; xStep = xp + 1; } else { xStep = xp; } // compute the final pixel pix = pixBuf[x]; // (255 * pix) / yStep pix = (pix * d) >> 23; // store the pixel for (i = 0; i < xStep; ++i) { *destPtr++ = (Guchar)pix; } } } gfree(pixBuf); gfree(lineBuf); } void Splash::scaleMaskYuXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf; Guint pix; Guchar *destPtr0, *destPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, d, d0, d1; int i; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; yq = scaledHeight % srcHeight; // Bresenham parameters for x scale xp = srcWidth / scaledWidth; xq = srcWidth % scaledWidth; // allocate buffers lineBuf = (Guchar *)gmalloc(srcWidth); // init y scale Bresenham yt = 0; destPtr0 = dest->data; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham if ((yt += yq) >= srcHeight) { yt -= srcHeight; yStep = yp + 1; } else { yStep = yp; } // read row from image (*src)(srcData, lineBuf); // init x scale Bresenham xt = 0; d0 = (255 << 23) / xp; d1 = (255 << 23) / (xp + 1); xx = 0; for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham if ((xt += xq) >= scaledWidth) { xt -= scaledWidth; xStep = xp + 1; d = d1; } else { xStep = xp; d = d0; } // compute the final pixel pix = 0; for (i = 0; i < xStep; ++i) { pix += lineBuf[xx++]; } // (255 * pix) / xStep pix = (pix * d) >> 23; // store the pixel for (i = 0; i < yStep; ++i) { destPtr = destPtr0 + i * scaledWidth + x; *destPtr = (Guchar)pix; } } destPtr0 += yStep * scaledWidth; } gfree(lineBuf); } void Splash::scaleMaskYuXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf; Guint pix; Guchar *destPtr0, *destPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; int i, j; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; yq = scaledHeight % srcHeight; // Bresenham parameters for x scale xp = scaledWidth / srcWidth; xq = scaledWidth % srcWidth; // allocate buffers lineBuf = (Guchar *)gmalloc(srcWidth); // init y scale Bresenham yt = 0; destPtr0 = dest->data; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham if ((yt += yq) >= srcHeight) { yt -= srcHeight; yStep = yp + 1; } else { yStep = yp; } // read row from image (*src)(srcData, lineBuf); // init x scale Bresenham xt = 0; xx = 0; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham if ((xt += xq) >= srcWidth) { xt -= srcWidth; xStep = xp + 1; } else { xStep = xp; } // compute the final pixel pix = lineBuf[x] ? 255 : 0; // store the pixel for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destPtr = destPtr0 + i * scaledWidth + xx + j; *destPtr++ = (Guchar)pix; } } xx += xStep; } destPtr0 += yStep * scaledWidth; } gfree(lineBuf); } void Splash::blitMask(SplashBitmap *src, int xDest, int yDest, SplashClipResult clipRes) { SplashPipe pipe; Guchar *p; int w, h, x, y; w = src->getWidth(); h = src->getHeight(); if (vectorAntialias && clipRes != splashClipAllInside) { pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); drawAAPixelInit(); p = src->getDataPtr(); for (y = 0; y < h; ++y) { for (x = 0; x < w; ++x) { pipe.shape = *p++; drawAAPixel(&pipe, xDest + x, yDest + y); } } } else { pipeInit(&pipe, xDest, yDest, state->fillPattern, NULL, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); p = src->getDataPtr(); if (clipRes == splashClipAllInside) { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { if (*p) { pipe.shape = *p; (this->*pipe.run)(&pipe); } else { pipeIncX(&pipe); } ++p; } } updateModX(xDest); updateModX(xDest + w - 1); updateModY(yDest); updateModY(yDest + h - 1); } else { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { if (*p && state->clip->test(xDest + x, yDest + y)) { pipe.shape = *p; (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); } else { pipeIncX(&pipe); } ++p; } } } } } SplashError Splash::drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat) { GBool ok; SplashBitmap *scaledImg; SplashClipResult clipRes; GBool minorAxisZero; int x0, y0, x1, y1, scaledWidth, scaledHeight; int nComps; if (debugMode) { printf("drawImage: srcMode=%d srcAlpha=%d w=%d h=%d mat=[%.2f %.2f %.2f %.2f %.2f %.2f]\n", srcMode, srcAlpha, w, h, (double)mat[0], (double)mat[1], (double)mat[2], (double)mat[3], (double)mat[4], (double)mat[5]); } // check color modes ok = gFalse; // make gcc happy nComps = 0; // make gcc happy switch (bitmap->mode) { case splashModeMono1: case splashModeMono8: ok = srcMode == splashModeMono8; nComps = 1; break; case splashModeRGB8: ok = srcMode == splashModeRGB8; nComps = 3; break; case splashModeBGR8: ok = srcMode == splashModeBGR8; nComps = 3; break; #if SPLASH_CMYK case splashModeCMYK8: ok = srcMode == splashModeCMYK8; nComps = 4; break; #endif default: ok = gFalse; break; } if (!ok) { return splashErrModeMismatch; } // check for singular matrix if (!splashCheckDet(mat[0], mat[1], mat[2], mat[3], 0.000001)) { return splashErrSingularMatrix; } minorAxisZero = mat[1] == 0 && mat[2] == 0; // scaling only if (mat[0] > 0 && minorAxisZero && mat[3] > 0) { x0 = imgCoordMungeLower(mat[4]); y0 = imgCoordMungeLower(mat[5]); x1 = imgCoordMungeUpper(mat[0] + mat[4]); y1 = imgCoordMungeUpper(mat[3] + mat[5]); // make sure narrow images cover at least one pixel if (x0 == x1) { ++x1; } if (y0 == y1) { ++y1; } clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); opClipRes = clipRes; if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight); blitImage(scaledImg, srcAlpha, x0, y0, clipRes); delete scaledImg; } // scaling plus vertical flip } else if (mat[0] > 0 && minorAxisZero && mat[3] < 0) { x0 = imgCoordMungeLower(mat[4]); y0 = imgCoordMungeLower(mat[3] + mat[5]); x1 = imgCoordMungeUpper(mat[0] + mat[4]); y1 = imgCoordMungeUpper(mat[5]); if (x0 == x1) { if (mat[4] + mat[0] * 0.5 < x0) { --x0; } else { ++x1; } } if (y0 == y1) { if (mat[5] + mat[1] * 0.5 < y0) { --y0; } else { ++y1; } } clipRes = state->clip->testRect(x0, y0, x1 - 1, y1 - 1); opClipRes = clipRes; if (clipRes != splashClipAllOutside) { scaledWidth = x1 - x0; scaledHeight = y1 - y0; scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, w, h, scaledWidth, scaledHeight); vertFlipImage(scaledImg, scaledWidth, scaledHeight, nComps); blitImage(scaledImg, srcAlpha, x0, y0, clipRes); delete scaledImg; } // all other cases } else { arbitraryTransformImage(src, srcData, srcMode, nComps, srcAlpha, w, h, mat); } return splashOk; } void Splash::arbitraryTransformImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat) { SplashBitmap *scaledImg; SplashClipResult clipRes, clipRes2; SplashPipe pipe; SplashColor pixel; int scaledWidth, scaledHeight, t0, t1; SplashCoord r00, r01, r10, r11, det, ir00, ir01, ir10, ir11; SplashCoord vx[4], vy[4]; int xMin, yMin, xMax, yMax; ImageSection section[3]; int nSections; int y, xa, xb, x, i, xx, yy; // compute the four vertices of the target quadrilateral vx[0] = mat[4]; vy[0] = mat[5]; vx[1] = mat[2] + mat[4]; vy[1] = mat[3] + mat[5]; vx[2] = mat[0] + mat[2] + mat[4]; vy[2] = mat[1] + mat[3] + mat[5]; vx[3] = mat[0] + mat[4]; vy[3] = mat[1] + mat[5]; // clipping xMin = imgCoordMungeLower(vx[0]); xMax = imgCoordMungeUpper(vx[0]); yMin = imgCoordMungeLower(vy[0]); yMax = imgCoordMungeUpper(vy[0]); for (i = 1; i < 4; ++i) { t0 = imgCoordMungeLower(vx[i]); if (t0 < xMin) { xMin = t0; } t0 = imgCoordMungeUpper(vx[i]); if (t0 > xMax) { xMax = t0; } t1 = imgCoordMungeLower(vy[i]); if (t1 < yMin) { yMin = t1; } t1 = imgCoordMungeUpper(vy[i]); if (t1 > yMax) { yMax = t1; } } clipRes = state->clip->testRect(xMin, yMin, xMax - 1, yMax - 1); opClipRes = clipRes; if (clipRes == splashClipAllOutside) { return; } // compute the scale factors if (mat[0] >= 0) { t0 = imgCoordMungeUpper(mat[0] + mat[4]) - imgCoordMungeLower(mat[4]); } else { t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[0] + mat[4]); } if (mat[1] >= 0) { t1 = imgCoordMungeUpper(mat[1] + mat[5]) - imgCoordMungeLower(mat[5]); } else { t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[1] + mat[5]); } scaledWidth = t0 > t1 ? t0 : t1; if (mat[2] >= 0) { t0 = imgCoordMungeUpper(mat[2] + mat[4]) - imgCoordMungeLower(mat[4]); } else { t0 = imgCoordMungeUpper(mat[4]) - imgCoordMungeLower(mat[2] + mat[4]); } if (mat[3] >= 0) { t1 = imgCoordMungeUpper(mat[3] + mat[5]) - imgCoordMungeLower(mat[5]); } else { t1 = imgCoordMungeUpper(mat[5]) - imgCoordMungeLower(mat[3] + mat[5]); } scaledHeight = t0 > t1 ? t0 : t1; if (scaledWidth == 0) { scaledWidth = 1; } if (scaledHeight == 0) { scaledHeight = 1; } // compute the inverse transform (after scaling) matrix r00 = mat[0] / scaledWidth; r01 = mat[1] / scaledWidth; r10 = mat[2] / scaledHeight; r11 = mat[3] / scaledHeight; det = r00 * r11 - r01 * r10; if (splashAbs(det) < 1e-6) { // this should be caught by the singular matrix check in drawImage return; } ir00 = r11 / det; ir01 = -r01 / det; ir10 = -r10 / det; ir11 = r00 / det; // scale the input image scaledImg = scaleImage(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight); // construct the three sections i = 0; if (vy[1] < vy[i]) { i = 1; } if (vy[2] < vy[i]) { i = 2; } if (vy[3] < vy[i]) { i = 3; } // NB: if using fixed point, 0.000001 will be truncated to zero, // so these two comparisons must be <=, not < if (splashAbs(vy[i] - vy[(i-1) & 3]) <= 0.000001 && vy[(i-1) & 3] < vy[(i+1) & 3]) { i = (i-1) & 3; } if (splashAbs(vy[i] - vy[(i+1) & 3]) <= 0.000001) { section[0].y0 = imgCoordMungeLower(vy[i]); section[0].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; if (vx[i] < vx[(i+1) & 3]) { section[0].ia0 = i; section[0].ia1 = (i+3) & 3; section[0].ib0 = (i+1) & 3; section[0].ib1 = (i+2) & 3; } else { section[0].ia0 = (i+1) & 3; section[0].ia1 = (i+2) & 3; section[0].ib0 = i; section[0].ib1 = (i+3) & 3; } nSections = 1; } else { section[0].y0 = imgCoordMungeLower(vy[i]); section[2].y1 = imgCoordMungeUpper(vy[(i+2) & 3]) - 1; section[0].ia0 = section[0].ib0 = i; section[2].ia1 = section[2].ib1 = (i+2) & 3; if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[0].ia1 = section[2].ia0 = (i+1) & 3; section[0].ib1 = section[2].ib0 = (i+3) & 3; } else { section[0].ia1 = section[2].ia0 = (i+3) & 3; section[0].ib1 = section[2].ib0 = (i+1) & 3; } if (vy[(i+1) & 3] < vy[(i+3) & 3]) { section[1].y0 = imgCoordMungeLower(vy[(i+1) & 3]); section[2].y0 = imgCoordMungeUpper(vy[(i+3) & 3]); if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[1].ia0 = (i+1) & 3; section[1].ia1 = (i+2) & 3; section[1].ib0 = i; section[1].ib1 = (i+3) & 3; } else { section[1].ia0 = i; section[1].ia1 = (i+3) & 3; section[1].ib0 = (i+1) & 3; section[1].ib1 = (i+2) & 3; } } else { section[1].y0 = imgCoordMungeLower(vy[(i+3) & 3]); section[2].y0 = imgCoordMungeUpper(vy[(i+1) & 3]); if (vx[(i+1) & 3] < vx[(i+3) & 3]) { section[1].ia0 = i; section[1].ia1 = (i+1) & 3; section[1].ib0 = (i+3) & 3; section[1].ib1 = (i+2) & 3; } else { section[1].ia0 = (i+3) & 3; section[1].ia1 = (i+2) & 3; section[1].ib0 = i; section[1].ib1 = (i+1) & 3; } } section[0].y1 = section[1].y0 - 1; section[1].y1 = section[2].y0 - 1; nSections = 3; } for (i = 0; i < nSections; ++i) { section[i].xa0 = vx[section[i].ia0]; section[i].ya0 = vy[section[i].ia0]; section[i].xa1 = vx[section[i].ia1]; section[i].ya1 = vy[section[i].ia1]; section[i].xb0 = vx[section[i].ib0]; section[i].yb0 = vy[section[i].ib0]; section[i].xb1 = vx[section[i].ib1]; section[i].yb1 = vy[section[i].ib1]; section[i].dxdya = (section[i].xa1 - section[i].xa0) / (section[i].ya1 - section[i].ya0); section[i].dxdyb = (section[i].xb1 - section[i].xb0) / (section[i].yb1 - section[i].yb0); } // initialize the pixel pipe pipeInit(&pipe, 0, 0, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), srcAlpha || (vectorAntialias && clipRes != splashClipAllInside), gFalse); if (vectorAntialias) { drawAAPixelInit(); } // make sure narrow images cover at least one pixel if (nSections == 1) { if (section[0].y0 == section[0].y1) { ++section[0].y1; clipRes = opClipRes = splashClipPartial; } } else { if (section[0].y0 == section[2].y1) { ++section[1].y1; clipRes = opClipRes = splashClipPartial; } } // scan all pixels inside the target region for (i = 0; i < nSections; ++i) { for (y = section[i].y0; y <= section[i].y1; ++y) { xa = imgCoordMungeLower(section[i].xa0 + ((SplashCoord)y + 0.5 - section[i].ya0) * section[i].dxdya); xb = imgCoordMungeUpper(section[i].xb0 + ((SplashCoord)y + 0.5 - section[i].yb0) * section[i].dxdyb); // make sure narrow images cover at least one pixel if (xa == xb) { ++xb; } if (clipRes != splashClipAllInside) { clipRes2 = state->clip->testSpan(xa, xb - 1, y); } else { clipRes2 = clipRes; } for (x = xa; x < xb; ++x) { // map (x+0.5, y+0.5) back to the scaled image xx = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir00 + ((SplashCoord)y + 0.5 - mat[5]) * ir10); yy = splashFloor(((SplashCoord)x + 0.5 - mat[4]) * ir01 + ((SplashCoord)y + 0.5 - mat[5]) * ir11); // xx should always be within bounds, but floating point // inaccuracy can cause problems if (xx < 0) { xx = 0; } else if (xx >= scaledWidth) { xx = scaledWidth - 1; } if (yy < 0) { yy = 0; } else if (yy >= scaledHeight) { yy = scaledHeight - 1; } scaledImg->getPixel(xx, yy, pixel); if (srcAlpha) { pipe.shape = scaledImg->alpha[yy * scaledWidth + xx]; } else { pipe.shape = 255; } if (vectorAntialias && clipRes2 != splashClipAllInside) { drawAAPixel(&pipe, x, y); } else { drawPixel(&pipe, x, y, clipRes2 == splashClipAllInside); } } } } delete scaledImg; } // Scale an image into a SplashBitmap. SplashBitmap *Splash::scaleImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight) { SplashBitmap *dest; dest = new SplashBitmap(scaledWidth, scaledHeight, 1, srcMode, srcAlpha); if (scaledHeight < srcHeight) { if (scaledWidth < srcWidth) { scaleImageYdXd(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } else { scaleImageYdXu(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } } else { if (scaledWidth < srcWidth) { scaleImageYuXd(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } else { scaleImageYuXu(src, srcData, srcMode, nComps, srcAlpha, srcWidth, srcHeight, scaledWidth, scaledHeight, dest); } } return dest; } void Splash::scaleImageYdXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf, *alphaLineBuf; Guint *pixBuf, *alphaPixBuf; Guint pix0, pix1, pix2; #if SPLASH_CMYK Guint pix3; #endif Guint alpha; Guchar *destPtr, *destAlphaPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; int i, j; // Bresenham parameters for y scale yp = srcHeight / scaledHeight; yq = srcHeight % scaledHeight; // Bresenham parameters for x scale xp = srcWidth / scaledWidth; xq = srcWidth % scaledWidth; // allocate buffers lineBuf = (Guchar *)gmallocn(srcWidth, nComps); pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); if (srcAlpha) { alphaLineBuf = (Guchar *)gmalloc(srcWidth); alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); } else { alphaLineBuf = NULL; alphaPixBuf = NULL; } // init y scale Bresenham yt = 0; destPtr = dest->data; destAlphaPtr = dest->alpha; for (y = 0; y < scaledHeight; ++y) { // y scale Bresenham if ((yt += yq) >= scaledHeight) { yt -= scaledHeight; yStep = yp + 1; } else { yStep = yp; } // read rows from image memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); if (srcAlpha) { memset(alphaPixBuf, 0, srcWidth * sizeof(int)); } for (i = 0; i < yStep; ++i) { (*src)(srcData, lineBuf, alphaLineBuf); for (j = 0; j < srcWidth * nComps; ++j) { pixBuf[j] += lineBuf[j]; } if (srcAlpha) { for (j = 0; j < srcWidth; ++j) { alphaPixBuf[j] += alphaLineBuf[j]; } } } // init x scale Bresenham xt = 0; d0 = (1 << 23) / (yStep * xp); d1 = (1 << 23) / (yStep * (xp + 1)); xx = xxa = 0; for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham if ((xt += xq) >= scaledWidth) { xt -= scaledWidth; xStep = xp + 1; d = d1; } else { xStep = xp; d = d0; } switch (srcMode) { case splashModeMono8: // compute the final pixel pix0 = 0; for (i = 0; i < xStep; ++i) { pix0 += pixBuf[xx++]; } // pix / xStep * yStep pix0 = (pix0 * d) >> 23; // store the pixel *destPtr++ = (Guchar)pix0; break; case splashModeRGB8: // compute the final pixel pix0 = pix1 = pix2 = 0; for (i = 0; i < xStep; ++i) { pix0 += pixBuf[xx]; pix1 += pixBuf[xx+1]; pix2 += pixBuf[xx+2]; xx += 3; } // pix / xStep * yStep pix0 = (pix0 * d) >> 23; pix1 = (pix1 * d) >> 23; pix2 = (pix2 * d) >> 23; // store the pixel *destPtr++ = (Guchar)pix0; *destPtr++ = (Guchar)pix1; *destPtr++ = (Guchar)pix2; break; case splashModeBGR8: // compute the final pixel pix0 = pix1 = pix2 = 0; for (i = 0; i < xStep; ++i) { pix0 += pixBuf[xx]; pix1 += pixBuf[xx+1]; pix2 += pixBuf[xx+2]; xx += 3; } // pix / xStep * yStep pix0 = (pix0 * d) >> 23; pix1 = (pix1 * d) >> 23; pix2 = (pix2 * d) >> 23; // store the pixel *destPtr++ = (Guchar)pix2; *destPtr++ = (Guchar)pix1; *destPtr++ = (Guchar)pix0; break; #if SPLASH_CMYK case splashModeCMYK8: // compute the final pixel pix0 = pix1 = pix2 = pix3 = 0; for (i = 0; i < xStep; ++i) { pix0 += pixBuf[xx]; pix1 += pixBuf[xx+1]; pix2 += pixBuf[xx+2]; pix3 += pixBuf[xx+3]; xx += 4; } // pix / xStep * yStep pix0 = (pix0 * d) >> 23; pix1 = (pix1 * d) >> 23; pix2 = (pix2 * d) >> 23; pix3 = (pix3 * d) >> 23; // store the pixel *destPtr++ = (Guchar)pix0; *destPtr++ = (Guchar)pix1; *destPtr++ = (Guchar)pix2; *destPtr++ = (Guchar)pix3; break; #endif case splashModeMono1: // mono1 is not allowed default: break; } // process alpha if (srcAlpha) { alpha = 0; for (i = 0; i < xStep; ++i, ++xxa) { alpha += alphaPixBuf[xxa]; } // alpha / xStep * yStep alpha = (alpha * d) >> 23; *destAlphaPtr++ = (Guchar)alpha; } } } gfree(alphaPixBuf); gfree(alphaLineBuf); gfree(pixBuf); gfree(lineBuf); } void Splash::scaleImageYdXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf, *alphaLineBuf; Guint *pixBuf, *alphaPixBuf; Guint pix[splashMaxColorComps]; Guint alpha; Guchar *destPtr, *destAlphaPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, d; int i, j; // Bresenham parameters for y scale yp = srcHeight / scaledHeight; yq = srcHeight % scaledHeight; // Bresenham parameters for x scale xp = scaledWidth / srcWidth; xq = scaledWidth % srcWidth; // allocate buffers lineBuf = (Guchar *)gmallocn(srcWidth, nComps); pixBuf = (Guint *)gmallocn(srcWidth, nComps * sizeof(int)); if (srcAlpha) { alphaLineBuf = (Guchar *)gmalloc(srcWidth); alphaPixBuf = (Guint *)gmallocn(srcWidth, sizeof(int)); } else { alphaLineBuf = NULL; alphaPixBuf = NULL; } // init y scale Bresenham yt = 0; destPtr = dest->data; destAlphaPtr = dest->alpha; for (y = 0; y < scaledHeight; ++y) { // y scale Bresenham if ((yt += yq) >= scaledHeight) { yt -= scaledHeight; yStep = yp + 1; } else { yStep = yp; } // read rows from image memset(pixBuf, 0, srcWidth * nComps * sizeof(int)); if (srcAlpha) { memset(alphaPixBuf, 0, srcWidth * sizeof(int)); } for (i = 0; i < yStep; ++i) { (*src)(srcData, lineBuf, alphaLineBuf); for (j = 0; j < srcWidth * nComps; ++j) { pixBuf[j] += lineBuf[j]; } if (srcAlpha) { for (j = 0; j < srcWidth; ++j) { alphaPixBuf[j] += alphaLineBuf[j]; } } } // init x scale Bresenham xt = 0; d = (1 << 23) / yStep; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham if ((xt += xq) >= srcWidth) { xt -= srcWidth; xStep = xp + 1; } else { xStep = xp; } // compute the final pixel for (i = 0; i < nComps; ++i) { // pixBuf[] / yStep pix[i] = (pixBuf[x * nComps + i] * d) >> 23; } // store the pixel switch (srcMode) { case splashModeMono1: // mono1 is not allowed break; case splashModeMono8: for (i = 0; i < xStep; ++i) { *destPtr++ = (Guchar)pix[0]; } break; case splashModeRGB8: for (i = 0; i < xStep; ++i) { *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; } break; case splashModeBGR8: for (i = 0; i < xStep; ++i) { *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[0]; } break; #if SPLASH_CMYK case splashModeCMYK8: for (i = 0; i < xStep; ++i) { *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[3]; } break; #endif } // process alpha if (srcAlpha) { // alphaPixBuf[] / yStep alpha = (alphaPixBuf[x] * d) >> 23; for (i = 0; i < xStep; ++i) { *destAlphaPtr++ = (Guchar)alpha; } } } } gfree(alphaPixBuf); gfree(alphaLineBuf); gfree(pixBuf); gfree(lineBuf); } void Splash::scaleImageYuXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf, *alphaLineBuf; Guint pix[splashMaxColorComps]; Guint alpha; Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx, xxa, d, d0, d1; int i, j; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; yq = scaledHeight % srcHeight; // Bresenham parameters for x scale xp = srcWidth / scaledWidth; xq = srcWidth % scaledWidth; // allocate buffers lineBuf = (Guchar *)gmallocn(srcWidth, nComps); if (srcAlpha) { alphaLineBuf = (Guchar *)gmalloc(srcWidth); } else { alphaLineBuf = NULL; } // init y scale Bresenham yt = 0; destPtr0 = dest->data; destAlphaPtr0 = dest->alpha; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham if ((yt += yq) >= srcHeight) { yt -= srcHeight; yStep = yp + 1; } else { yStep = yp; } // read row from image (*src)(srcData, lineBuf, alphaLineBuf); // init x scale Bresenham xt = 0; d0 = (1 << 23) / xp; d1 = (1 << 23) / (xp + 1); xx = xxa = 0; for (x = 0; x < scaledWidth; ++x) { // x scale Bresenham if ((xt += xq) >= scaledWidth) { xt -= scaledWidth; xStep = xp + 1; d = d1; } else { xStep = xp; d = d0; } // compute the final pixel for (i = 0; i < nComps; ++i) { pix[i] = 0; } for (i = 0; i < xStep; ++i) { for (j = 0; j < nComps; ++j, ++xx) { pix[j] += lineBuf[xx]; } } for (i = 0; i < nComps; ++i) { // pix[] / xStep pix[i] = (pix[i] * d) >> 23; } // store the pixel switch (srcMode) { case splashModeMono1: // mono1 is not allowed break; case splashModeMono8: for (i = 0; i < yStep; ++i) { destPtr = destPtr0 + (i * scaledWidth + x) * nComps; *destPtr++ = (Guchar)pix[0]; } break; case splashModeRGB8: for (i = 0; i < yStep; ++i) { destPtr = destPtr0 + (i * scaledWidth + x) * nComps; *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; } break; case splashModeBGR8: for (i = 0; i < yStep; ++i) { destPtr = destPtr0 + (i * scaledWidth + x) * nComps; *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[0]; } break; #if SPLASH_CMYK case splashModeCMYK8: for (i = 0; i < yStep; ++i) { destPtr = destPtr0 + (i * scaledWidth + x) * nComps; *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[3]; } break; #endif } // process alpha if (srcAlpha) { alpha = 0; for (i = 0; i < xStep; ++i, ++xxa) { alpha += alphaLineBuf[xxa]; } // alpha / xStep alpha = (alpha * d) >> 23; for (i = 0; i < yStep; ++i) { destAlphaPtr = destAlphaPtr0 + i * scaledWidth + x; *destAlphaPtr = (Guchar)alpha; } } } destPtr0 += yStep * scaledWidth * nComps; if (srcAlpha) { destAlphaPtr0 += yStep * scaledWidth; } } gfree(alphaLineBuf); gfree(lineBuf); } void Splash::scaleImageYuXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest) { Guchar *lineBuf, *alphaLineBuf; Guint pix[splashMaxColorComps]; Guint alpha; Guchar *destPtr0, *destPtr, *destAlphaPtr0, *destAlphaPtr; int yp, yq, xp, xq, yt, y, yStep, xt, x, xStep, xx; int i, j; // Bresenham parameters for y scale yp = scaledHeight / srcHeight; yq = scaledHeight % srcHeight; // Bresenham parameters for x scale xp = scaledWidth / srcWidth; xq = scaledWidth % srcWidth; // allocate buffers lineBuf = (Guchar *)gmallocn(srcWidth, nComps); if (srcAlpha) { alphaLineBuf = (Guchar *)gmalloc(srcWidth); } else { alphaLineBuf = NULL; } // init y scale Bresenham yt = 0; destPtr0 = dest->data; destAlphaPtr0 = dest->alpha; for (y = 0; y < srcHeight; ++y) { // y scale Bresenham if ((yt += yq) >= srcHeight) { yt -= srcHeight; yStep = yp + 1; } else { yStep = yp; } // read row from image (*src)(srcData, lineBuf, alphaLineBuf); // init x scale Bresenham xt = 0; xx = 0; for (x = 0; x < srcWidth; ++x) { // x scale Bresenham if ((xt += xq) >= srcWidth) { xt -= srcWidth; xStep = xp + 1; } else { xStep = xp; } // compute the final pixel for (i = 0; i < nComps; ++i) { pix[i] = lineBuf[x * nComps + i]; } // store the pixel switch (srcMode) { case splashModeMono1: // mono1 is not allowed break; case splashModeMono8: for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; *destPtr++ = (Guchar)pix[0]; } } break; case splashModeRGB8: for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; } } break; case splashModeBGR8: for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[0]; } } break; #if SPLASH_CMYK case splashModeCMYK8: for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destPtr = destPtr0 + (i * scaledWidth + xx + j) * nComps; *destPtr++ = (Guchar)pix[0]; *destPtr++ = (Guchar)pix[1]; *destPtr++ = (Guchar)pix[2]; *destPtr++ = (Guchar)pix[3]; } } break; #endif } // process alpha if (srcAlpha) { alpha = alphaLineBuf[x]; for (i = 0; i < yStep; ++i) { for (j = 0; j < xStep; ++j) { destAlphaPtr = destAlphaPtr0 + i * scaledWidth + xx + j; *destAlphaPtr = (Guchar)alpha; } } } xx += xStep; } destPtr0 += yStep * scaledWidth * nComps; if (srcAlpha) { destAlphaPtr0 += yStep * scaledWidth; } } gfree(alphaLineBuf); gfree(lineBuf); } void Splash::vertFlipImage(SplashBitmap *img, int width, int height, int nComps) { Guchar *lineBuf; Guchar *p0, *p1; int w; w = width * nComps; lineBuf = (Guchar *)gmalloc(w); for (p0 = img->data, p1 = img->data + (height - 1) * w; p0 < p1; p0 += w, p1 -= w) { memcpy(lineBuf, p0, w); memcpy(p0, p1, w); memcpy(p1, lineBuf, w); } if (img->alpha) { for (p0 = img->alpha, p1 = img->alpha + (height - 1) * width; p0 < p1; p0 += width, p1 -= width) { memcpy(lineBuf, p0, width); memcpy(p0, p1, width); memcpy(p1, lineBuf, width); } } gfree(lineBuf); } void Splash::blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest, SplashClipResult clipRes) { SplashPipe pipe; SplashColor pixel; Guchar *ap; int w, h, x0, y0, x1, y1, x, y; // split the image into clipped and unclipped regions w = src->getWidth(); h = src->getHeight(); if (clipRes == splashClipAllInside) { x0 = 0; y0 = 0; x1 = w; y1 = h; } else { if (state->clip->getNumPaths()) { x0 = x1 = w; y0 = y1 = h; } else { if ((x0 = splashCeil(state->clip->getXMin()) - xDest) < 0) { x0 = 0; } if ((y0 = splashCeil(state->clip->getYMin()) - yDest) < 0) { y0 = 0; } if ((x1 = splashFloor(state->clip->getXMax()) - xDest) > w) { x1 = w; } if (x1 < x0) { x1 = x0; } if ((y1 = splashFloor(state->clip->getYMax()) - yDest) > h) { y1 = h; } if (y1 < y0) { y1 = y0; } } } // draw the unclipped region if (x0 < w && y0 < h && x0 < x1 && y0 < y1) { pipeInit(&pipe, xDest + x0, yDest + y0, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); if (srcAlpha) { for (y = y0; y < y1; ++y) { pipeSetXY(&pipe, xDest + x0, yDest + y); ap = src->getAlphaPtr() + y * w + x0; for (x = x0; x < x1; ++x) { src->getPixel(x, y, pixel); pipe.shape = *ap++; (this->*pipe.run)(&pipe); } } } else { for (y = y0; y < y1; ++y) { pipeSetXY(&pipe, xDest + x0, yDest + y); for (x = x0; x < x1; ++x) { src->getPixel(x, y, pixel); (this->*pipe.run)(&pipe); } } } updateModX(xDest + x0); updateModX(xDest + x1 - 1); updateModY(yDest + y0); updateModY(yDest + y1 - 1); } // draw the clipped regions if (y0 > 0) { blitImageClipped(src, srcAlpha, 0, 0, xDest, yDest, w, y0); } if (y1 < h) { blitImageClipped(src, srcAlpha, 0, y1, xDest, yDest + y1, w, h - y1); } if (x0 > 0 && y0 < y1) { blitImageClipped(src, srcAlpha, 0, y0, xDest, yDest + y0, x0, y1 - y0); } if (x1 < w && y0 < y1) { blitImageClipped(src, srcAlpha, x1, y0, xDest + x1, yDest + y0, w - x1, y1 - y0); } } void Splash::blitImageClipped(SplashBitmap *src, GBool srcAlpha, int xSrc, int ySrc, int xDest, int yDest, int w, int h) { SplashPipe pipe; SplashColor pixel; Guchar *ap; int x, y; if (vectorAntialias) { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), gTrue, gFalse); drawAAPixelInit(); if (srcAlpha) { for (y = 0; y < h; ++y) { ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); pipe.shape = *ap++; drawAAPixel(&pipe, xDest + x, yDest + y); } } } else { for (y = 0; y < h; ++y) { for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); pipe.shape = 255; drawAAPixel(&pipe, xDest + x, yDest + y); } } } } else { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), srcAlpha, gFalse); if (srcAlpha) { for (y = 0; y < h; ++y) { ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { if (state->clip->test(xDest + x, yDest + y)) { src->getPixel(xSrc + x, ySrc + y, pixel); pipe.shape = *ap++; (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); } else { pipeIncX(&pipe); ++ap; } } } } else { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { if (state->clip->test(xDest + x, yDest + y)) { src->getPixel(xSrc + x, ySrc + y, pixel); (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); } else { pipeIncX(&pipe); } } } } } } SplashError Splash::composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, GBool noClip, GBool nonIsolated) { SplashPipe pipe; SplashColor pixel; Guchar alpha; Guchar *ap; int x, y; if (src->mode != bitmap->mode) { return splashErrModeMismatch; } if (src->alpha) { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), gTrue, nonIsolated); if (noClip) { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); alpha = *ap++; // this uses shape instead of alpha, which isn't technically // correct, but works out the same pipe.shape = alpha; (this->*pipe.run)(&pipe); } } updateModX(xDest); updateModX(xDest + w - 1); updateModY(yDest); updateModY(yDest + h - 1); } else { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); ap = src->getAlphaPtr() + (ySrc + y) * src->getWidth() + xSrc; for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); alpha = *ap++; if (state->clip->test(xDest + x, yDest + y)) { // this uses shape instead of alpha, which isn't technically // correct, but works out the same pipe.shape = alpha; (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); } else { pipeIncX(&pipe); } } } } } else { pipeInit(&pipe, xDest, yDest, NULL, pixel, (Guchar)splashRound(state->fillAlpha * 255), gFalse, nonIsolated); if (noClip) { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); (this->*pipe.run)(&pipe); } } updateModX(xDest); updateModX(xDest + w - 1); updateModY(yDest); updateModY(yDest + h - 1); } else { for (y = 0; y < h; ++y) { pipeSetXY(&pipe, xDest, yDest + y); for (x = 0; x < w; ++x) { src->getPixel(xSrc + x, ySrc + y, pixel); if (state->clip->test(xDest + x, yDest + y)) { (this->*pipe.run)(&pipe); updateModX(xDest + x); updateModY(yDest + y); } else { pipeIncX(&pipe); } } } } } return splashOk; } void Splash::compositeBackground(SplashColorPtr color) { SplashColorPtr p; Guchar *q; Guchar alpha, alpha1, c, color0, color1, color2; #if SPLASH_CMYK Guchar color3; #endif int x, y, mask; switch (bitmap->mode) { case splashModeMono1: color0 = color[0]; for (y = 0; y < bitmap->height; ++y) { p = &bitmap->data[y * bitmap->rowSize]; q = &bitmap->alpha[y * bitmap->width]; mask = 0x80; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; alpha1 = 255 - alpha; c = (*p & mask) ? 0xff : 0x00; c = div255(alpha1 * color0 + alpha * c); if (c & 0x80) { *p |= mask; } else { *p &= ~mask; } if (!(mask >>= 1)) { mask = 0x80; ++p; } } } break; case splashModeMono8: color0 = color[0]; for (y = 0; y < bitmap->height; ++y) { p = &bitmap->data[y * bitmap->rowSize]; q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; alpha1 = 255 - alpha; p[0] = div255(alpha1 * color0 + alpha * p[0]); ++p; } } break; case splashModeRGB8: case splashModeBGR8: color0 = color[0]; color1 = color[1]; color2 = color[2]; for (y = 0; y < bitmap->height; ++y) { p = &bitmap->data[y * bitmap->rowSize]; q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; alpha1 = 255 - alpha; p[0] = div255(alpha1 * color0 + alpha * p[0]); p[1] = div255(alpha1 * color1 + alpha * p[1]); p[2] = div255(alpha1 * color2 + alpha * p[2]); p += 3; } } break; #if SPLASH_CMYK case splashModeCMYK8: color0 = color[0]; color1 = color[1]; color2 = color[2]; color3 = color[3]; for (y = 0; y < bitmap->height; ++y) { p = &bitmap->data[y * bitmap->rowSize]; q = &bitmap->alpha[y * bitmap->width]; for (x = 0; x < bitmap->width; ++x) { alpha = *q++; alpha1 = 255 - alpha; p[0] = div255(alpha1 * color0 + alpha * p[0]); p[1] = div255(alpha1 * color1 + alpha * p[1]); p[2] = div255(alpha1 * color2 + alpha * p[2]); p[3] = div255(alpha1 * color3 + alpha * p[3]); p += 4; } } break; #endif } memset(bitmap->alpha, 255, bitmap->width * bitmap->height); } SplashError Splash::blitTransparent(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h) { SplashColorPtr p, q; int x, y, mask, srcMask; if (src->mode != bitmap->mode) { return splashErrModeMismatch; } switch (bitmap->mode) { case splashModeMono1: for (y = 0; y < h; ++y) { p = &bitmap->data[(yDest + y) * bitmap->rowSize + (xDest >> 3)]; mask = 0x80 >> (xDest & 7); q = &src->data[(ySrc + y) * src->rowSize + (xSrc >> 3)]; srcMask = 0x80 >> (xSrc & 7); for (x = 0; x < w; ++x) { if (*q & srcMask) { *p |= mask; } else { *p &= ~mask; } if (!(mask >>= 1)) { mask = 0x80; ++p; } if (!(srcMask >>= 1)) { srcMask = 0x80; ++q; } } } break; case splashModeMono8: for (y = 0; y < h; ++y) { p = &bitmap->data[(yDest + y) * bitmap->rowSize + xDest]; q = &src->data[(ySrc + y) * src->rowSize + xSrc]; for (x = 0; x < w; ++x) { *p++ = *q++; } } break; case splashModeRGB8: case splashModeBGR8: for (y = 0; y < h; ++y) { p = &bitmap->data[(yDest + y) * bitmap->rowSize + 3 * xDest]; q = &src->data[(ySrc + y) * src->rowSize + 3 * xSrc]; for (x = 0; x < w; ++x) { *p++ = *q++; *p++ = *q++; *p++ = *q++; } } break; #if SPLASH_CMYK case splashModeCMYK8: for (y = 0; y < h; ++y) { p = &bitmap->data[(yDest + y) * bitmap->rowSize + 4 * xDest]; q = &src->data[(ySrc + y) * src->rowSize + 4 * xSrc]; for (x = 0; x < w; ++x) { *p++ = *q++; *p++ = *q++; *p++ = *q++; *p++ = *q++; } } break; #endif } if (bitmap->alpha) { for (y = 0; y < h; ++y) { q = &bitmap->alpha[(yDest + y) * bitmap->width + xDest]; for (x = 0; x < w; ++x) { *q++ = 0x00; } } } return splashOk; } SplashPath *Splash::makeStrokePath(SplashPath *path, SplashCoord w, GBool flatten) { SplashPath *pathIn, *dashPath, *pathOut; SplashCoord d, dx, dy, wdx, wdy, dxNext, dyNext, wdxNext, wdyNext; SplashCoord crossprod, dotprod, miter, m; GBool first, last, closed; int subpathStart0, subpathStart1, seg, i0, i1, j0, j1, k0, k1; int left0, left1, left2, right0, right1, right2, join0, join1, join2; int leftFirst, rightFirst, firstPt; pathOut = new SplashPath(); if (path->length == 0) { return pathOut; } if (flatten) { pathIn = flattenPath(path, state->matrix, state->flatness); if (state->lineDashLength > 0) { dashPath = makeDashedPath(pathIn); delete pathIn; pathIn = dashPath; if (pathIn->length == 0) { delete pathIn; return pathOut; } } } else { pathIn = path; } subpathStart0 = subpathStart1 = 0; // make gcc happy seg = 0; // make gcc happy closed = gFalse; // make gcc happy left0 = left1 = right0 = right1 = join0 = join1 = 0; // make gcc happy leftFirst = rightFirst = firstPt = 0; // make gcc happy i0 = 0; for (i1 = i0; !(pathIn->flags[i1] & splashPathLast) && i1 + 1 < pathIn->length && pathIn->pts[i1+1].x == pathIn->pts[i1].x && pathIn->pts[i1+1].y == pathIn->pts[i1].y; ++i1) ; while (i1 < pathIn->length) { if ((first = pathIn->flags[i0] & splashPathFirst)) { subpathStart0 = i0; subpathStart1 = i1; seg = 0; closed = pathIn->flags[i0] & splashPathClosed; } j0 = i1 + 1; if (j0 < pathIn->length) { for (j1 = j0; !(pathIn->flags[j1] & splashPathLast) && j1 + 1 < pathIn->length && pathIn->pts[j1+1].x == pathIn->pts[j1].x && pathIn->pts[j1+1].y == pathIn->pts[j1].y; ++j1) ; } else { j1 = j0; } if (pathIn->flags[i1] & splashPathLast) { if (first && state->lineCap == splashLineCapRound) { // special case: zero-length subpath with round line caps --> // draw a circle pathOut->moveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, pathIn->pts[i0].y); pathOut->curveTo(pathIn->pts[i0].x + (SplashCoord)0.5 * w, pathIn->pts[i0].y + bezierCircle2 * w, pathIn->pts[i0].x + bezierCircle2 * w, pathIn->pts[i0].y + (SplashCoord)0.5 * w, pathIn->pts[i0].x, pathIn->pts[i0].y + (SplashCoord)0.5 * w); pathOut->curveTo(pathIn->pts[i0].x - bezierCircle2 * w, pathIn->pts[i0].y + (SplashCoord)0.5 * w, pathIn->pts[i0].x - (SplashCoord)0.5 * w, pathIn->pts[i0].y + bezierCircle2 * w, pathIn->pts[i0].x - (SplashCoord)0.5 * w, pathIn->pts[i0].y); pathOut->curveTo(pathIn->pts[i0].x - (SplashCoord)0.5 * w, pathIn->pts[i0].y - bezierCircle2 * w, pathIn->pts[i0].x - bezierCircle2 * w, pathIn->pts[i0].y - (SplashCoord)0.5 * w, pathIn->pts[i0].x, pathIn->pts[i0].y - (SplashCoord)0.5 * w); pathOut->curveTo(pathIn->pts[i0].x + bezierCircle2 * w, pathIn->pts[i0].y - (SplashCoord)0.5 * w, pathIn->pts[i0].x + (SplashCoord)0.5 * w, pathIn->pts[i0].y - bezierCircle2 * w, pathIn->pts[i0].x + (SplashCoord)0.5 * w, pathIn->pts[i0].y); pathOut->close(); } i0 = j0; i1 = j1; continue; } last = pathIn->flags[j1] & splashPathLast; if (last) { k0 = subpathStart1 + 1; } else { k0 = j1 + 1; } for (k1 = k0; !(pathIn->flags[k1] & splashPathLast) && k1 + 1 < pathIn->length && pathIn->pts[k1+1].x == pathIn->pts[k1].x && pathIn->pts[k1+1].y == pathIn->pts[k1].y; ++k1) ; // compute the deltas for segment (i1, j0) #if USE_FIXEDPOINT // the 1/d value can be small, which introduces significant // inaccuracies in fixed point mode d = splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, pathIn->pts[j0].x, pathIn->pts[j0].y); dx = (pathIn->pts[j0].x - pathIn->pts[i1].x) / d; dy = (pathIn->pts[j0].y - pathIn->pts[i1].y) / d; #else d = (SplashCoord)1 / splashDist(pathIn->pts[i1].x, pathIn->pts[i1].y, pathIn->pts[j0].x, pathIn->pts[j0].y); dx = d * (pathIn->pts[j0].x - pathIn->pts[i1].x); dy = d * (pathIn->pts[j0].y - pathIn->pts[i1].y); #endif wdx = (SplashCoord)0.5 * w * dx; wdy = (SplashCoord)0.5 * w * dy; // draw the start cap pathOut->moveTo(pathIn->pts[i0].x - wdy, pathIn->pts[i0].y + wdx); if (i0 == subpathStart0) { firstPt = pathOut->length - 1; } if (first && !closed) { switch (state->lineCap) { case splashLineCapButt: pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); break; case splashLineCapRound: pathOut->curveTo(pathIn->pts[i0].x - wdy - bezierCircle * wdx, pathIn->pts[i0].y + wdx - bezierCircle * wdy, pathIn->pts[i0].x - wdx - bezierCircle * wdy, pathIn->pts[i0].y - wdy + bezierCircle * wdx, pathIn->pts[i0].x - wdx, pathIn->pts[i0].y - wdy); pathOut->curveTo(pathIn->pts[i0].x - wdx + bezierCircle * wdy, pathIn->pts[i0].y - wdy - bezierCircle * wdx, pathIn->pts[i0].x + wdy - bezierCircle * wdx, pathIn->pts[i0].y - wdx - bezierCircle * wdy, pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); break; case splashLineCapProjecting: pathOut->lineTo(pathIn->pts[i0].x - wdx - wdy, pathIn->pts[i0].y + wdx - wdy); pathOut->lineTo(pathIn->pts[i0].x - wdx + wdy, pathIn->pts[i0].y - wdx - wdy); pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); break; } } else { pathOut->lineTo(pathIn->pts[i0].x + wdy, pathIn->pts[i0].y - wdx); } // draw the left side of the segment rectangle left2 = pathOut->length - 1; pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); // draw the end cap if (last && !closed) { switch (state->lineCap) { case splashLineCapButt: pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); break; case splashLineCapRound: pathOut->curveTo(pathIn->pts[j0].x + wdy + bezierCircle * wdx, pathIn->pts[j0].y - wdx + bezierCircle * wdy, pathIn->pts[j0].x + wdx + bezierCircle * wdy, pathIn->pts[j0].y + wdy - bezierCircle * wdx, pathIn->pts[j0].x + wdx, pathIn->pts[j0].y + wdy); pathOut->curveTo(pathIn->pts[j0].x + wdx - bezierCircle * wdy, pathIn->pts[j0].y + wdy + bezierCircle * wdx, pathIn->pts[j0].x - wdy + bezierCircle * wdx, pathIn->pts[j0].y + wdx + bezierCircle * wdy, pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); break; case splashLineCapProjecting: pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx, pathIn->pts[j0].y - wdx + wdy); pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx, pathIn->pts[j0].y + wdx + wdy); pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); break; } } else { pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); } // draw the right side of the segment rectangle // (NB: if stroke adjustment is enabled, the closepath operation MUST // add a segment because this segment is used for a hint) right2 = pathOut->length - 1; pathOut->close(state->strokeAdjust); // draw the join join2 = pathOut->length; if (!last || closed) { // compute the deltas for segment (j1, k0) #if USE_FIXEDPOINT // the 1/d value can be small, which introduces significant // inaccuracies in fixed point mode d = splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, pathIn->pts[k0].x, pathIn->pts[k0].y); dxNext = (pathIn->pts[k0].x - pathIn->pts[j1].x) / d; dyNext = (pathIn->pts[k0].y - pathIn->pts[j1].y) / d; #else d = (SplashCoord)1 / splashDist(pathIn->pts[j1].x, pathIn->pts[j1].y, pathIn->pts[k0].x, pathIn->pts[k0].y); dxNext = d * (pathIn->pts[k0].x - pathIn->pts[j1].x); dyNext = d * (pathIn->pts[k0].y - pathIn->pts[j1].y); #endif wdxNext = (SplashCoord)0.5 * w * dxNext; wdyNext = (SplashCoord)0.5 * w * dyNext; // compute the join parameters crossprod = dx * dyNext - dy * dxNext; dotprod = -(dx * dxNext + dy * dyNext); if (dotprod > 0.9999) { // avoid a divide-by-zero -- set miter to something arbitrary // such that sqrt(miter) will exceed miterLimit (and m is never // used in that situation) // (note: the comparison value (0.9999) has to be less than // 1-epsilon, where epsilon is the smallest value // representable in the fixed point format) miter = (state->miterLimit + 1) * (state->miterLimit + 1); m = 0; } else { miter = (SplashCoord)2 / ((SplashCoord)1 - dotprod); if (miter < 1) { // this can happen because of floating point inaccuracies miter = 1; } m = splashSqrt(miter - 1); } // round join if (state->lineJoin == splashLineJoinRound) { pathOut->moveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, pathIn->pts[j0].y); pathOut->curveTo(pathIn->pts[j0].x + (SplashCoord)0.5 * w, pathIn->pts[j0].y + bezierCircle2 * w, pathIn->pts[j0].x + bezierCircle2 * w, pathIn->pts[j0].y + (SplashCoord)0.5 * w, pathIn->pts[j0].x, pathIn->pts[j0].y + (SplashCoord)0.5 * w); pathOut->curveTo(pathIn->pts[j0].x - bezierCircle2 * w, pathIn->pts[j0].y + (SplashCoord)0.5 * w, pathIn->pts[j0].x - (SplashCoord)0.5 * w, pathIn->pts[j0].y + bezierCircle2 * w, pathIn->pts[j0].x - (SplashCoord)0.5 * w, pathIn->pts[j0].y); pathOut->curveTo(pathIn->pts[j0].x - (SplashCoord)0.5 * w, pathIn->pts[j0].y - bezierCircle2 * w, pathIn->pts[j0].x - bezierCircle2 * w, pathIn->pts[j0].y - (SplashCoord)0.5 * w, pathIn->pts[j0].x, pathIn->pts[j0].y - (SplashCoord)0.5 * w); pathOut->curveTo(pathIn->pts[j0].x + bezierCircle2 * w, pathIn->pts[j0].y - (SplashCoord)0.5 * w, pathIn->pts[j0].x + (SplashCoord)0.5 * w, pathIn->pts[j0].y - bezierCircle2 * w, pathIn->pts[j0].x + (SplashCoord)0.5 * w, pathIn->pts[j0].y); } else { pathOut->moveTo(pathIn->pts[j0].x, pathIn->pts[j0].y); // angle < 180 if (crossprod < 0) { pathOut->lineTo(pathIn->pts[j0].x - wdyNext, pathIn->pts[j0].y + wdxNext); // miter join inside limit if (state->lineJoin == splashLineJoinMiter && splashSqrt(miter) <= state->miterLimit) { pathOut->lineTo(pathIn->pts[j0].x - wdy + wdx * m, pathIn->pts[j0].y + wdx + wdy * m); pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); // bevel join or miter join outside limit } else { pathOut->lineTo(pathIn->pts[j0].x - wdy, pathIn->pts[j0].y + wdx); } // angle >= 180 } else { pathOut->lineTo(pathIn->pts[j0].x + wdy, pathIn->pts[j0].y - wdx); // miter join inside limit if (state->lineJoin == splashLineJoinMiter && splashSqrt(miter) <= state->miterLimit) { pathOut->lineTo(pathIn->pts[j0].x + wdy + wdx * m, pathIn->pts[j0].y - wdx + wdy * m); pathOut->lineTo(pathIn->pts[j0].x + wdyNext, pathIn->pts[j0].y - wdxNext); // bevel join or miter join outside limit } else { pathOut->lineTo(pathIn->pts[j0].x + wdyNext, pathIn->pts[j0].y - wdxNext); } } } pathOut->close(); } // add stroke adjustment hints if (state->strokeAdjust) { if (seg == 0 && !closed) { if (state->lineCap == splashLineCapButt) { pathOut->addStrokeAdjustHint(firstPt, left2 + 1, firstPt, firstPt + 1); if (last) { pathOut->addStrokeAdjustHint(firstPt, left2 + 1, left2 + 1, left2 + 2); } } else if (state->lineCap == splashLineCapProjecting) { if (last) { pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, firstPt + 1, firstPt + 2); pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 2, left2 + 2, left2 + 3); } else { pathOut->addStrokeAdjustHint(firstPt + 1, left2 + 1, firstPt + 1, firstPt + 2); } } } if (seg >= 1) { if (seg >= 2) { pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); pathOut->addStrokeAdjustHint(left1, right1, join0, left2); } else { pathOut->addStrokeAdjustHint(left1, right1, firstPt, left2); } pathOut->addStrokeAdjustHint(left1, right1, right2 + 1, right2 + 1); } left0 = left1; left1 = left2; right0 = right1; right1 = right2; join0 = join1; join1 = join2; if (seg == 0) { leftFirst = left2; rightFirst = right2; } if (last) { if (seg >= 2) { pathOut->addStrokeAdjustHint(left1, right1, left0 + 1, right0); pathOut->addStrokeAdjustHint(left1, right1, join0, pathOut->length - 1); } else { pathOut->addStrokeAdjustHint(left1, right1, firstPt, pathOut->length - 1); } if (closed) { pathOut->addStrokeAdjustHint(left1, right1, firstPt, leftFirst); pathOut->addStrokeAdjustHint(left1, right1, rightFirst + 1, rightFirst + 1); pathOut->addStrokeAdjustHint(leftFirst, rightFirst, left1 + 1, right1); pathOut->addStrokeAdjustHint(leftFirst, rightFirst, join1, pathOut->length - 1); } if (!closed && seg > 0) { if (state->lineCap == splashLineCapButt) { pathOut->addStrokeAdjustHint(left1 - 1, left1 + 1, left1 + 1, left1 + 2); } else if (state->lineCap == splashLineCapProjecting) { pathOut->addStrokeAdjustHint(left1 - 1, left1 + 2, left1 + 2, left1 + 3); } } } } i0 = j0; i1 = j1; ++seg; } if (pathIn != path) { delete pathIn; } return pathOut; } void Splash::dumpPath(SplashPath *path) { int i; for (i = 0; i < path->length; ++i) { printf(" %3d: x=%8.2f y=%8.2f%s%s%s%s\n", i, (double)path->pts[i].x, (double)path->pts[i].y, (path->flags[i] & splashPathFirst) ? " first" : "", (path->flags[i] & splashPathLast) ? " last" : "", (path->flags[i] & splashPathClosed) ? " closed" : "", (path->flags[i] & splashPathCurve) ? " curve" : ""); } } void Splash::dumpXPath(SplashXPath *path) { int i; for (i = 0; i < path->length; ++i) { printf(" %4d: x0=%8.2f y0=%8.2f x1=%8.2f y1=%8.2f %s%s%s\n", i, (double)path->segs[i].x0, (double)path->segs[i].y0, (double)path->segs[i].x1, (double)path->segs[i].y1, (path->segs[i].flags & splashXPathHoriz) ? "H" : " ", (path->segs[i].flags & splashXPathVert) ? "V" : " ", (path->segs[i].flags & splashXPathFlip) ? "P" : " "); } } xpdf-3.03/splash/SplashScreen.h0000644000076400007640000000323711622305345015755 0ustar dereknderekn//======================================================================== // // SplashScreen.h // //======================================================================== #ifndef SPLASHSCREEN_H #define SPLASHSCREEN_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" //------------------------------------------------------------------------ // SplashScreen //------------------------------------------------------------------------ class SplashScreen { public: SplashScreen(SplashScreenParams *params); SplashScreen(SplashScreen *screen); ~SplashScreen(); SplashScreen *copy() { return new SplashScreen(this); } // Return the computed pixel value (0=black, 1=white) for the gray // level at (, ). int test(int x, int y, Guchar value) { int xx, yy; xx = x & sizeM1; yy = y & sizeM1; return value < mat[(yy << log2Size) + xx] ? 0 : 1; } // Returns true if value is above the white threshold or below the // black threshold, i.e., if the corresponding halftone will be // solid white or black. GBool isStatic(Guchar value) { return value < minVal || value >= maxVal; } private: void buildDispersedMatrix(int i, int j, int val, int delta, int offset); void buildClusteredMatrix(); int distance(int x0, int y0, int x1, int y1); void buildSCDMatrix(int r); Guchar *mat; // threshold matrix int size; // size of the threshold matrix int sizeM1; // size - 1 int log2Size; // log2(size) Guchar minVal; // any pixel value below minVal generates // solid black Guchar maxVal; // any pixel value above maxVal generates // solid white }; #endif xpdf-3.03/splash/SplashFTFont.h0000644000076400007640000000251611622305345015675 0ustar dereknderekn//======================================================================== // // SplashFTFont.h // //======================================================================== #ifndef SPLASHFTFONT_H #define SPLASHFTFONT_H #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include FT_FREETYPE_H #include "SplashFont.h" class SplashFTFontFile; //------------------------------------------------------------------------ // SplashFTFont //------------------------------------------------------------------------ class SplashFTFont: public SplashFont { public: SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA); virtual ~SplashFTFont(); // Munge xFrac and yFrac before calling SplashFont::getGlyph. virtual GBool getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Rasterize a glyph. The and values are the same // as described for getGlyph. virtual GBool makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Return the path for a glyph. virtual SplashPath *getGlyphPath(int c); private: FT_Size sizeObj; FT_Matrix matrix; FT_Matrix textMatrix; SplashCoord textScale; }; #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #endif xpdf-3.03/splash/SplashXPath.cc0000644000076400007640000002732211622305345015721 0ustar dereknderekn//======================================================================== // // SplashXPath.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #if HAVE_STD_SORT #include #endif #include "gmem.h" #include "SplashMath.h" #include "SplashPath.h" #include "SplashXPath.h" //------------------------------------------------------------------------ struct SplashXPathPoint { SplashCoord x, y; }; struct SplashXPathAdjust { int firstPt, lastPt; // range of points GBool vert; // vertical or horizontal hint SplashCoord x0a, x0b, // hint boundaries xma, xmb, x1a, x1b; SplashCoord x0, x1, xm; // adjusted coordinates }; //------------------------------------------------------------------------ // Transform a point from user space to device space. inline void SplashXPath::transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo) { // [ m[0] m[1] 0 ] // [xo yo 1] = [xi yi 1] * [ m[2] m[3] 0 ] // [ m[4] m[5] 1 ] *xo = xi * matrix[0] + yi * matrix[2] + matrix[4]; *yo = xi * matrix[1] + yi * matrix[3] + matrix[5]; } //------------------------------------------------------------------------ // SplashXPath //------------------------------------------------------------------------ SplashXPath::SplashXPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool closeSubpaths) { SplashPathHint *hint; SplashXPathPoint *pts; SplashXPathAdjust *adjusts, *adjust; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xsp, ysp; SplashCoord adj0, adj1; int curSubpath, curSubpathX, i, j; // transform the points pts = (SplashXPathPoint *)gmallocn(path->length, sizeof(SplashXPathPoint)); for (i = 0; i < path->length; ++i) { transform(matrix, path->pts[i].x, path->pts[i].y, &pts[i].x, &pts[i].y); } // set up the stroke adjustment hints if (path->hints) { adjusts = (SplashXPathAdjust *)gmallocn(path->hintsLength, sizeof(SplashXPathAdjust)); for (i = 0; i < path->hintsLength; ++i) { hint = &path->hints[i]; x0 = pts[hint->ctrl0 ].x; y0 = pts[hint->ctrl0 ].y; x1 = pts[hint->ctrl0 + 1].x; y1 = pts[hint->ctrl0 + 1].y; x2 = pts[hint->ctrl1 ].x; y2 = pts[hint->ctrl1 ].y; x3 = pts[hint->ctrl1 + 1].x; y3 = pts[hint->ctrl1 + 1].y; if (x0 == x1 && x2 == x3) { adjusts[i].vert = gTrue; adj0 = x0; adj1 = x2; } else if (y0 == y1 && y2 == y3) { adjusts[i].vert = gFalse; adj0 = y0; adj1 = y2; } else { gfree(adjusts); adjusts = NULL; break; } if (adj0 > adj1) { x0 = adj0; adj0 = adj1; adj1 = x0; } adjusts[i].x0a = adj0 - 0.01; adjusts[i].x0b = adj0 + 0.01; adjusts[i].xma = (SplashCoord)0.5 * (adj0 + adj1) - 0.01; adjusts[i].xmb = (SplashCoord)0.5 * (adj0 + adj1) + 0.01; adjusts[i].x1a = adj1 - 0.01; adjusts[i].x1b = adj1 + 0.01; // rounding both edge coordinates can result in lines of // different widths (e.g., adj=10.1, adj1=11.3 --> x0=10, x1=11; // adj0=10.4, adj1=11.6 --> x0=10, x1=12), but it has the // benefit of making adjacent strokes/fills line up without any // gaps between them x0 = splashRound(adj0); x1 = splashRound(adj1); if (x1 == x0) { x1 = x1 + 1; } adjusts[i].x0 = (SplashCoord)x0; adjusts[i].x1 = (SplashCoord)x1 - 0.01; adjusts[i].xm = (SplashCoord)0.5 * (adjusts[i].x0 + adjusts[i].x1); adjusts[i].firstPt = hint->firstPt; adjusts[i].lastPt = hint->lastPt; } } else { adjusts = NULL; } // perform stroke adjustment if (adjusts) { for (i = 0, adjust = adjusts; i < path->hintsLength; ++i, ++adjust) { for (j = adjust->firstPt; j <= adjust->lastPt; ++j) { strokeAdjust(adjust, &pts[j].x, &pts[j].y); } } gfree(adjusts); } segs = NULL; length = size = 0; x0 = y0 = xsp = ysp = 0; // make gcc happy adj0 = adj1 = 0; // make gcc happy curSubpath = 0; curSubpathX = 0; i = 0; while (i < path->length) { // first point in subpath - skip it if (path->flags[i] & splashPathFirst) { x0 = pts[i].x; y0 = pts[i].y; xsp = x0; ysp = y0; curSubpath = i; curSubpathX = length; ++i; } else { // curve segment if (path->flags[i] & splashPathCurve) { x1 = pts[i].x; y1 = pts[i].y; x2 = pts[i+1].x; y2 = pts[i+1].y; x3 = pts[i+2].x; y3 = pts[i+2].y; addCurve(x0, y0, x1, y1, x2, y2, x3, y3, flatness, (path->flags[i-1] & splashPathFirst), (path->flags[i+2] & splashPathLast), !closeSubpaths && (path->flags[i-1] & splashPathFirst) && !(path->flags[i-1] & splashPathClosed), !closeSubpaths && (path->flags[i+2] & splashPathLast) && !(path->flags[i+2] & splashPathClosed)); x0 = x3; y0 = y3; i += 3; // line segment } else { x1 = pts[i].x; y1 = pts[i].y; addSegment(x0, y0, x1, y1); x0 = x1; y0 = y1; ++i; } // close a subpath if (closeSubpaths && (path->flags[i-1] & splashPathLast) && (pts[i-1].x != pts[curSubpath].x || pts[i-1].y != pts[curSubpath].y)) { addSegment(x0, y0, xsp, ysp); } } } gfree(pts); } // Apply the stroke adjust hints to point : (*, *). void SplashXPath::strokeAdjust(SplashXPathAdjust *adjust, SplashCoord *xp, SplashCoord *yp) { SplashCoord x, y; if (adjust->vert) { x = *xp; if (x > adjust->x0a && x < adjust->x0b) { *xp = adjust->x0; } else if (x > adjust->xma && x < adjust->xmb) { *xp = adjust->xm; } else if (x > adjust->x1a && x < adjust->x1b) { *xp = adjust->x1; } } else { y = *yp; if (y > adjust->x0a && y < adjust->x0b) { *yp = adjust->x0; } else if (y > adjust->xma && y < adjust->xmb) { *yp = adjust->xm; } else if (y > adjust->x1a && y < adjust->x1b) { *yp = adjust->x1; } } } SplashXPath::SplashXPath(SplashXPath *xPath) { length = xPath->length; size = xPath->size; segs = (SplashXPathSeg *)gmallocn(size, sizeof(SplashXPathSeg)); memcpy(segs, xPath->segs, length * sizeof(SplashXPathSeg)); } SplashXPath::~SplashXPath() { gfree(segs); } // Add space for more segments void SplashXPath::grow(int nSegs) { if (length + nSegs > size) { if (size == 0) { size = 32; } while (size < length + nSegs) { size *= 2; } segs = (SplashXPathSeg *)greallocn(segs, size, sizeof(SplashXPathSeg)); } } void SplashXPath::addCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3, SplashCoord flatness, GBool first, GBool last, GBool end0, GBool end1) { SplashCoord cx[splashMaxCurveSplits + 1][3]; SplashCoord cy[splashMaxCurveSplits + 1][3]; int cNext[splashMaxCurveSplits + 1]; SplashCoord xl0, xl1, xl2, xr0, xr1, xr2, xr3, xx1, xx2, xh; SplashCoord yl0, yl1, yl2, yr0, yr1, yr2, yr3, yy1, yy2, yh; SplashCoord dx, dy, mx, my, d1, d2, flatness2; int p1, p2, p3; #if USE_FIXEDPOINT flatness2 = flatness; #else flatness2 = flatness * flatness; #endif // initial segment p1 = 0; p2 = splashMaxCurveSplits; cx[p1][0] = x0; cy[p1][0] = y0; cx[p1][1] = x1; cy[p1][1] = y1; cx[p1][2] = x2; cy[p1][2] = y2; cx[p2][0] = x3; cy[p2][0] = y3; cNext[p1] = p2; while (p1 < splashMaxCurveSplits) { // get the next segment xl0 = cx[p1][0]; yl0 = cy[p1][0]; xx1 = cx[p1][1]; yy1 = cy[p1][1]; xx2 = cx[p1][2]; yy2 = cy[p1][2]; p2 = cNext[p1]; xr3 = cx[p2][0]; yr3 = cy[p2][0]; // compute the distances from the control points to the // midpoint of the straight line (this is a bit of a hack, but // it's much faster than computing the actual distances to the // line) mx = (xl0 + xr3) * 0.5; my = (yl0 + yr3) * 0.5; #if USE_FIXEDPOINT d1 = splashDist(xx1, yy1, mx, my); d2 = splashDist(xx2, yy2, mx, my); #else dx = xx1 - mx; dy = yy1 - my; d1 = dx*dx + dy*dy; dx = xx2 - mx; dy = yy2 - my; d2 = dx*dx + dy*dy; #endif // if the curve is flat enough, or no more subdivisions are // allowed, add the straight line segment if (p2 - p1 == 1 || (d1 <= flatness2 && d2 <= flatness2)) { addSegment(xl0, yl0, xr3, yr3); p1 = p2; // otherwise, subdivide the curve } else { xl1 = (xl0 + xx1) * 0.5; yl1 = (yl0 + yy1) * 0.5; xh = (xx1 + xx2) * 0.5; yh = (yy1 + yy2) * 0.5; xl2 = (xl1 + xh) * 0.5; yl2 = (yl1 + yh) * 0.5; xr2 = (xx2 + xr3) * 0.5; yr2 = (yy2 + yr3) * 0.5; xr1 = (xh + xr2) * 0.5; yr1 = (yh + yr2) * 0.5; xr0 = (xl2 + xr1) * 0.5; yr0 = (yl2 + yr1) * 0.5; // add the new subdivision points p3 = (p1 + p2) / 2; cx[p1][1] = xl1; cy[p1][1] = yl1; cx[p1][2] = xl2; cy[p1][2] = yl2; cNext[p1] = p3; cx[p3][0] = xr0; cy[p3][0] = yr0; cx[p3][1] = xr1; cy[p3][1] = yr1; cx[p3][2] = xr2; cy[p3][2] = yr2; cNext[p3] = p2; } } } void SplashXPath::addSegment(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { grow(1); segs[length].x0 = x0; segs[length].y0 = y0; segs[length].x1 = x1; segs[length].y1 = y1; segs[length].flags = 0; if (y1 == y0) { segs[length].dxdy = segs[length].dydx = 0; segs[length].flags |= splashXPathHoriz; if (x1 == x0) { segs[length].flags |= splashXPathVert; } } else if (x1 == x0) { segs[length].dxdy = segs[length].dydx = 0; segs[length].flags |= splashXPathVert; } else { #if USE_FIXEDPOINT if (FixedPoint::divCheck(x1 - x0, y1 - y0, &segs[length].dxdy)) { segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; } else { segs[length].dxdy = segs[length].dydx = 0; if (splashAbs(x1 - x0) > splashAbs(y1 - y0)) { segs[length].flags |= splashXPathHoriz; } else { segs[length].flags |= splashXPathVert; } } #else segs[length].dxdy = (x1 - x0) / (y1 - y0); segs[length].dydx = (SplashCoord)1 / segs[length].dxdy; #endif } if (y0 > y1) { segs[length].flags |= splashXPathFlip; } ++length; } void SplashXPath::aaScale() { SplashXPathSeg *seg; int i; for (i = 0, seg = segs; i < length; ++i, ++seg) { seg->x0 *= splashAASize; seg->y0 *= splashAASize; seg->x1 *= splashAASize; seg->y1 *= splashAASize; } } #if HAVE_STD_SORT struct cmpXPathSegsFunctor { bool operator()(const SplashXPathSeg &seg0, const SplashXPathSeg &seg1) { SplashCoord x0, y0, x1, y1; if (seg0.flags & splashXPathFlip) { x0 = seg0.x1; y0 = seg0.y1; } else { x0 = seg0.x0; y0 = seg0.y0; } if (seg1.flags & splashXPathFlip) { x1 = seg1.x1; y1 = seg1.y1; } else { x1 = seg1.x0; y1 = seg1.y0; } return (y0 != y1) ? (y0 < y1) : (x0 < x1); } }; #else // HAVE_STD_SORT static int cmpXPathSegs(const void *arg0, const void *arg1) { SplashXPathSeg *seg0 = (SplashXPathSeg *)arg0; SplashXPathSeg *seg1 = (SplashXPathSeg *)arg1; SplashCoord x0, y0, x1, y1; if (seg0->flags & splashXPathFlip) { x0 = seg0->x1; y0 = seg0->y1; } else { x0 = seg0->x0; y0 = seg0->y0; } if (seg1->flags & splashXPathFlip) { x1 = seg1->x1; y1 = seg1->y1; } else { x1 = seg1->x0; y1 = seg1->y0; } if (y0 != y1) { return (y0 > y1) ? 1 : -1; } if (x0 != x1) { return (x0 > x1) ? 1 : -1; } return 0; } #endif // HAVE_STD_SORT void SplashXPath::sort() { #if HAVE_STD_SORT std::sort(segs, segs + length, cmpXPathSegsFunctor()); #else qsort(segs, length, sizeof(SplashXPathSeg), &cmpXPathSegs); #endif } xpdf-3.03/splash/SplashClip.cc0000644000076400007640000002374611622305345015572 0ustar dereknderekn//======================================================================== // // SplashClip.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "SplashErrorCodes.h" #include "SplashPath.h" #include "SplashXPath.h" #include "SplashXPathScanner.h" #include "SplashBitmap.h" #include "SplashClip.h" //------------------------------------------------------------------------ // SplashClip.flags //------------------------------------------------------------------------ #define splashClipEO 0x01 // use even-odd rule //------------------------------------------------------------------------ // SplashClip //------------------------------------------------------------------------ SplashClip::SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, GBool antialiasA) { antialias = antialiasA; if (x0 < x1) { xMin = x0; xMax = x1; } else { xMin = x1; xMax = x0; } if (y0 < y1) { yMin = y0; yMax = y1; } else { yMin = y1; yMax = y0; } xMinI = splashFloor(xMin); yMinI = splashFloor(yMin); xMaxI = splashCeil(xMax) - 1; yMaxI = splashCeil(yMax) - 1; paths = NULL; flags = NULL; scanners = NULL; length = size = 0; } SplashClip::SplashClip(SplashClip *clip) { int yMinAA, yMaxAA; int i; antialias = clip->antialias; xMin = clip->xMin; yMin = clip->yMin; xMax = clip->xMax; yMax = clip->yMax; xMinI = clip->xMinI; yMinI = clip->yMinI; xMaxI = clip->xMaxI; yMaxI = clip->yMaxI; length = clip->length; size = clip->size; paths = (SplashXPath **)gmallocn(size, sizeof(SplashXPath *)); flags = (Guchar *)gmallocn(size, sizeof(Guchar)); scanners = (SplashXPathScanner **) gmallocn(size, sizeof(SplashXPathScanner *)); for (i = 0; i < length; ++i) { paths[i] = clip->paths[i]->copy(); flags[i] = clip->flags[i]; if (antialias) { yMinAA = yMinI * splashAASize; yMaxAA = (yMaxI + 1) * splashAASize - 1; } else { yMinAA = yMinI; yMaxAA = yMaxI; } scanners[i] = new SplashXPathScanner(paths[i], flags[i] & splashClipEO, yMinAA, yMaxAA); } } SplashClip::~SplashClip() { int i; for (i = 0; i < length; ++i) { delete paths[i]; delete scanners[i]; } gfree(paths); gfree(flags); gfree(scanners); } void SplashClip::grow(int nPaths) { if (length + nPaths > size) { if (size == 0) { size = 32; } while (size < length + nPaths) { size *= 2; } paths = (SplashXPath **)greallocn(paths, size, sizeof(SplashXPath *)); flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); scanners = (SplashXPathScanner **) greallocn(scanners, size, sizeof(SplashXPathScanner *)); } } void SplashClip::resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { int i; for (i = 0; i < length; ++i) { delete paths[i]; delete scanners[i]; } gfree(paths); gfree(flags); gfree(scanners); paths = NULL; flags = NULL; scanners = NULL; length = size = 0; if (x0 < x1) { xMin = x0; xMax = x1; } else { xMin = x1; xMax = x0; } if (y0 < y1) { yMin = y0; yMax = y1; } else { yMin = y1; yMax = y0; } xMinI = splashFloor(xMin); yMinI = splashFloor(yMin); xMaxI = splashCeil(xMax) - 1; yMaxI = splashCeil(yMax) - 1; } SplashError SplashClip::clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { if (x0 < x1) { if (x0 > xMin) { xMin = x0; xMinI = splashFloor(xMin); } if (x1 < xMax) { xMax = x1; xMaxI = splashCeil(xMax) - 1; } } else { if (x1 > xMin) { xMin = x1; xMinI = splashFloor(xMin); } if (x0 < xMax) { xMax = x0; xMaxI = splashCeil(xMax) - 1; } } if (y0 < y1) { if (y0 > yMin) { yMin = y0; yMinI = splashFloor(yMin); } if (y1 < yMax) { yMax = y1; yMaxI = splashCeil(yMax) - 1; } } else { if (y1 > yMin) { yMin = y1; yMinI = splashFloor(yMin); } if (y0 < yMax) { yMax = y0; yMaxI = splashCeil(yMax) - 1; } } return splashOk; } SplashError SplashClip::clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool eo) { SplashXPath *xPath; int yMinAA, yMaxAA; xPath = new SplashXPath(path, matrix, flatness, gTrue); // check for an empty path if (xPath->length == 0) { xMax = xMin - 1; yMax = yMin - 1; xMaxI = splashCeil(xMax) - 1; yMaxI = splashCeil(yMax) - 1; delete xPath; // check for a rectangle } else if (xPath->length == 4 && ((xPath->segs[0].x0 == xPath->segs[0].x1 && xPath->segs[0].x0 == xPath->segs[1].x0 && xPath->segs[0].x0 == xPath->segs[3].x1 && xPath->segs[2].x0 == xPath->segs[2].x1 && xPath->segs[2].x0 == xPath->segs[1].x1 && xPath->segs[2].x0 == xPath->segs[3].x0 && xPath->segs[1].y0 == xPath->segs[1].y1 && xPath->segs[1].y0 == xPath->segs[0].y1 && xPath->segs[1].y0 == xPath->segs[2].y0 && xPath->segs[3].y0 == xPath->segs[3].y1 && xPath->segs[3].y0 == xPath->segs[0].y0 && xPath->segs[3].y0 == xPath->segs[2].y1) || (xPath->segs[0].y0 == xPath->segs[0].y1 && xPath->segs[0].y0 == xPath->segs[1].y0 && xPath->segs[0].y0 == xPath->segs[3].y1 && xPath->segs[2].y0 == xPath->segs[2].y1 && xPath->segs[2].y0 == xPath->segs[1].y1 && xPath->segs[2].y0 == xPath->segs[3].y0 && xPath->segs[1].x0 == xPath->segs[1].x1 && xPath->segs[1].x0 == xPath->segs[0].x1 && xPath->segs[1].x0 == xPath->segs[2].x0 && xPath->segs[3].x0 == xPath->segs[3].x1 && xPath->segs[3].x0 == xPath->segs[0].x0 && xPath->segs[3].x0 == xPath->segs[2].x1))) { clipToRect(xPath->segs[0].x0, xPath->segs[0].y0, xPath->segs[2].x0, xPath->segs[2].y0); delete xPath; } else { grow(1); if (antialias) { xPath->aaScale(); } xPath->sort(); paths[length] = xPath; flags[length] = eo ? splashClipEO : 0; if (antialias) { yMinAA = yMinI * splashAASize; yMaxAA = (yMaxI + 1) * splashAASize - 1; } else { yMinAA = yMinI; yMaxAA = yMaxI; } scanners[length] = new SplashXPathScanner(xPath, eo, yMinAA, yMaxAA); ++length; } return splashOk; } GBool SplashClip::test(int x, int y) { int i; // check the rectangle if (x < xMinI || x > xMaxI || y < yMinI || y > yMaxI) { return gFalse; } // check the paths if (antialias) { for (i = 0; i < length; ++i) { if (!scanners[i]->test(x * splashAASize, y * splashAASize)) { return gFalse; } } } else { for (i = 0; i < length; ++i) { if (!scanners[i]->test(x, y)) { return gFalse; } } } return gTrue; } SplashClipResult SplashClip::testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax) { // This tests the rectangle: // x = [rectXMin, rectXMax + 1) (note: rect coords are ints) // y = [rectYMin, rectYMax + 1) // against the clipping region: // x = [xMin, xMax) (note: clipping coords are fp) // y = [yMin, yMax) if ((SplashCoord)(rectXMax + 1) <= xMin || (SplashCoord)rectXMin >= xMax || (SplashCoord)(rectYMax + 1) <= yMin || (SplashCoord)rectYMin >= yMax) { return splashClipAllOutside; } if ((SplashCoord)rectXMin >= xMin && (SplashCoord)(rectXMax + 1) <= xMax && (SplashCoord)rectYMin >= yMin && (SplashCoord)(rectYMax + 1) <= yMax && length == 0) { return splashClipAllInside; } return splashClipPartial; } SplashClipResult SplashClip::testSpan(int spanXMin, int spanXMax, int spanY) { int i; // This tests the rectangle: // x = [spanXMin, spanXMax + 1) (note: span coords are ints) // y = [spanY, spanY + 1) // against the clipping region: // x = [xMin, xMax) (note: clipping coords are fp) // y = [yMin, yMax) if ((SplashCoord)(spanXMax + 1) <= xMin || (SplashCoord)spanXMin >= xMax || (SplashCoord)(spanY + 1) <= yMin || (SplashCoord)spanY >= yMax) { return splashClipAllOutside; } if (!((SplashCoord)spanXMin >= xMin && (SplashCoord)(spanXMax + 1) <= xMax && (SplashCoord)spanY >= yMin && (SplashCoord)(spanY + 1) <= yMax)) { return splashClipPartial; } if (antialias) { for (i = 0; i < length; ++i) { if (!scanners[i]->testSpan(spanXMin * splashAASize, spanXMax * splashAASize + (splashAASize - 1), spanY * splashAASize)) { return splashClipPartial; } } } else { for (i = 0; i < length; ++i) { if (!scanners[i]->testSpan(spanXMin, spanXMax, spanY)) { return splashClipPartial; } } } return splashClipAllInside; } void SplashClip::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { int xx0, xx1, xx, yy, i; SplashColorPtr p; // zero out pixels with x < xMin xx0 = *x0 * splashAASize; xx1 = splashFloor(xMin * splashAASize); if (xx1 > aaBuf->getWidth()) { xx1 = aaBuf->getWidth(); } if (xx0 < xx1) { xx0 &= ~7; for (yy = 0; yy < splashAASize; ++yy) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); for (xx = xx0; xx + 7 < xx1; xx += 8) { *p++ = 0; } if (xx < xx1) { *p &= 0xff >> (xx1 & 7); } } *x0 = splashFloor(xMin); } // zero out pixels with x > xMax xx0 = splashFloor(xMax * splashAASize) + 1; if (xx0 < 0) { xx0 = 0; } xx1 = (*x1 + 1) * splashAASize; if (xx0 < xx1) { for (yy = 0; yy < splashAASize; ++yy) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx0 >> 3); xx = xx0; if (xx & 7) { *p &= 0xff00 >> (xx & 7); xx = (xx & ~7) + 8; ++p; } for (; xx < xx1; xx += 8) { *p++ = 0; } } *x1 = splashFloor(xMax); } // check the paths for (i = 0; i < length; ++i) { scanners[i]->clipAALine(aaBuf, x0, x1, y); } } xpdf-3.03/splash/SplashXPath.h0000644000076400007640000000515311622305345015561 0ustar dereknderekn//======================================================================== // // SplashXPath.h // //======================================================================== #ifndef SPLASHXPATH_H #define SPLASHXPATH_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" class SplashPath; struct SplashXPathAdjust; //------------------------------------------------------------------------ #define splashMaxCurveSplits (1 << 10) //------------------------------------------------------------------------ // SplashXPathSeg //------------------------------------------------------------------------ struct SplashXPathSeg { SplashCoord x0, y0; // first endpoint SplashCoord x1, y1; // second endpoint SplashCoord dxdy; // slope: delta-x / delta-y SplashCoord dydx; // slope: delta-y / delta-x Guint flags; }; #define splashXPathHoriz 0x01 // segment is vertical (y0 == y1) // (dxdy is undef) #define splashXPathVert 0x02 // segment is horizontal (x0 == x1) // (dydx is undef) #define splashXPathFlip 0x04 // y0 > y1 //------------------------------------------------------------------------ // SplashXPath //------------------------------------------------------------------------ class SplashXPath { public: // Expands (converts to segments) and flattens (converts curves to // lines) . Transforms all points from user space to device // space, via . If is true, closes all open // subpaths. SplashXPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool closeSubpaths); // Copy an expanded path. SplashXPath *copy() { return new SplashXPath(this); } ~SplashXPath(); // Multiply all coordinates by splashAASize, in preparation for // anti-aliased rendering. void aaScale(); // Sort by upper coordinate (lower y), in y-major order. void sort(); private: SplashXPath(SplashXPath *xPath); void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo); void strokeAdjust(SplashXPathAdjust *adjust, SplashCoord *xp, SplashCoord *yp); void grow(int nSegs); void addCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3, SplashCoord flatness, GBool first, GBool last, GBool end0, GBool end1); void addSegment(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); SplashXPathSeg *segs; int length, size; // length and size of segs array friend class SplashXPathScanner; friend class SplashClip; friend class Splash; }; #endif xpdf-3.03/splash/SplashXPathScanner.cc0000644000076400007640000003124611622305345017233 0ustar dereknderekn//======================================================================== // // SplashXPathScanner.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #if HAVE_STD_SORT #include #endif #include "gmem.h" #include "SplashMath.h" #include "SplashXPath.h" #include "SplashBitmap.h" #include "SplashXPathScanner.h" //------------------------------------------------------------------------ struct SplashIntersect { int y; int x0, x1; // intersection of segment with [y, y+1) int count; // EO/NZWN counter increment }; #if HAVE_STD_SORT struct cmpIntersectFunctor { bool operator()(const SplashIntersect &i0, const SplashIntersect &i1) { return (i0.y != i1.y) ? (i0.y < i1.y) : (i0.x0 < i1.x0); } }; #else // HAVE_STD_SORT static int cmpIntersect(const void *p0, const void *p1) { SplashIntersect *i0 = (SplashIntersect *)p0; SplashIntersect *i1 = (SplashIntersect *)p1; int cmp; if ((cmp = i0->y - i1->y) == 0) { cmp = i0->x0 - i1->x0; } return cmp; } #endif // HAVE_STD_SORT //------------------------------------------------------------------------ // SplashXPathScanner //------------------------------------------------------------------------ SplashXPathScanner::SplashXPathScanner(SplashXPath *xPathA, GBool eoA, int clipYMin, int clipYMax) { SplashXPathSeg *seg; SplashCoord xMinFP, yMinFP, xMaxFP, yMaxFP; int i; xPath = xPathA; eo = eoA; partialClip = gFalse; // compute the bbox if (xPath->length == 0) { xMin = yMin = 1; xMax = yMax = 0; } else { seg = &xPath->segs[0]; if (seg->x0 <= seg->x1) { xMinFP = seg->x0; xMaxFP = seg->x1; } else { xMinFP = seg->x1; xMaxFP = seg->x0; } if (seg->flags & splashXPathFlip) { yMinFP = seg->y1; yMaxFP = seg->y0; } else { yMinFP = seg->y0; yMaxFP = seg->y1; } for (i = 1; i < xPath->length; ++i) { seg = &xPath->segs[i]; if (seg->x0 < xMinFP) { xMinFP = seg->x0; } else if (seg->x0 > xMaxFP) { xMaxFP = seg->x0; } if (seg->x1 < xMinFP) { xMinFP = seg->x1; } else if (seg->x1 > xMaxFP) { xMaxFP = seg->x1; } if (seg->flags & splashXPathFlip) { if (seg->y0 > yMaxFP) { yMaxFP = seg->y0; } } else { if (seg->y1 > yMaxFP) { yMaxFP = seg->y1; } } } xMin = splashFloor(xMinFP); xMax = splashFloor(xMaxFP); yMin = splashFloor(yMinFP); yMax = splashFloor(yMaxFP); if (clipYMin > yMin) { yMin = clipYMin; partialClip = gTrue; } if (clipYMax < yMax) { yMax = clipYMax; partialClip = gTrue; } } allInter = NULL; inter = NULL; computeIntersections(); interY = yMin - 1; } SplashXPathScanner::~SplashXPathScanner() { gfree(inter); gfree(allInter); } void SplashXPathScanner::getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) { *xMinA = xMin / splashAASize; *yMinA = yMin / splashAASize; *xMaxA = xMax / splashAASize; *yMaxA = yMax / splashAASize; } void SplashXPathScanner::getSpanBounds(int y, int *spanXMin, int *spanXMax) { int interBegin, interEnd, xx, i; if (y < yMin || y > yMax) { interBegin = interEnd = 0; } else { interBegin = inter[y - yMin]; interEnd = inter[y - yMin + 1]; } if (interBegin < interEnd) { *spanXMin = allInter[interBegin].x0; xx = allInter[interBegin].x1; for (i = interBegin + 1; i < interEnd; ++i) { if (allInter[i].x1 > xx) { xx = allInter[i].x1; } } *spanXMax = xx; } else { *spanXMin = xMax + 1; *spanXMax = xMax; } } GBool SplashXPathScanner::test(int x, int y) { int interBegin, interEnd, count, i; if (y < yMin || y > yMax) { return gFalse; } interBegin = inter[y - yMin]; interEnd = inter[y - yMin + 1]; count = 0; for (i = interBegin; i < interEnd && allInter[i].x0 <= x; ++i) { if (x <= allInter[i].x1) { return gTrue; } count += allInter[i].count; } return eo ? (count & 1) : (count != 0); } GBool SplashXPathScanner::testSpan(int x0, int x1, int y) { int interBegin, interEnd, count, xx1, i; if (y < yMin || y > yMax) { return gFalse; } interBegin = inter[y - yMin]; interEnd = inter[y - yMin + 1]; count = 0; for (i = interBegin; i < interEnd && allInter[i].x1 < x0; ++i) { count += allInter[i].count; } // invariant: the subspan [x0,xx1] is inside the path xx1 = x0 - 1; while (xx1 < x1) { if (i >= interEnd) { return gFalse; } if (allInter[i].x0 > xx1 + 1 && !(eo ? (count & 1) : (count != 0))) { return gFalse; } if (allInter[i].x1 > xx1) { xx1 = allInter[i].x1; } count += allInter[i].count; ++i; } return gTrue; } GBool SplashXPathScanner::getNextSpan(int y, int *x0, int *x1) { int interEnd, xx0, xx1; if (y < yMin || y > yMax) { return gFalse; } if (interY != y) { interY = y; interIdx = inter[y - yMin]; interCount = 0; } interEnd = inter[y - yMin + 1]; if (interIdx >= interEnd) { return gFalse; } xx0 = allInter[interIdx].x0; xx1 = allInter[interIdx].x1; interCount += allInter[interIdx].count; ++interIdx; while (interIdx < interEnd && (allInter[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { if (allInter[interIdx].x1 > xx1) { xx1 = allInter[interIdx].x1; } interCount += allInter[interIdx].count; ++interIdx; } *x0 = xx0; *x1 = xx1; return gTrue; } void SplashXPathScanner::computeIntersections() { SplashXPathSeg *seg; SplashCoord segXMin, segXMax, segYMin, segYMax, xx0, xx1; int x, y, y0, y1, i; if (yMin > yMax) { return; } // build the list of all intersections allInterLen = 0; allInterSize = 16; allInter = (SplashIntersect *)gmallocn(allInterSize, sizeof(SplashIntersect)); for (i = 0; i < xPath->length; ++i) { seg = &xPath->segs[i]; if (seg->flags & splashXPathFlip) { segYMin = seg->y1; segYMax = seg->y0; } else { segYMin = seg->y0; segYMax = seg->y1; } if (seg->flags & splashXPathHoriz) { y = splashFloor(seg->y0); if (y >= yMin && y <= yMax) { addIntersection(segYMin, segYMax, seg->flags, y, splashFloor(seg->x0), splashFloor(seg->x1)); } } else if (seg->flags & splashXPathVert) { y0 = splashFloor(segYMin); if (y0 < yMin) { y0 = yMin; } y1 = splashFloor(segYMax); if (y1 > yMax) { y1 = yMax; } x = splashFloor(seg->x0); for (y = y0; y <= y1; ++y) { addIntersection(segYMin, segYMax, seg->flags, y, x, x); } } else { if (seg->x0 < seg->x1) { segXMin = seg->x0; segXMax = seg->x1; } else { segXMin = seg->x1; segXMax = seg->x0; } y0 = splashFloor(segYMin); if (y0 < yMin) { y0 = yMin; } y1 = splashFloor(segYMax); if (y1 > yMax) { y1 = yMax; } // this loop could just add seg->dxdy to xx1 on each iteration, // but that introduces numerical accuracy problems xx1 = seg->x0 + ((SplashCoord)y0 - seg->y0) * seg->dxdy; for (y = y0; y <= y1; ++y) { xx0 = xx1; xx1 = seg->x0 + ((SplashCoord)(y + 1) - seg->y0) * seg->dxdy; // the segment may not actually extend to the top and/or bottom edges if (xx0 < segXMin) { xx0 = segXMin; } else if (xx0 > segXMax) { xx0 = segXMax; } if (xx1 < segXMin) { xx1 = segXMin; } else if (xx1 > segXMax) { xx1 = segXMax; } addIntersection(segYMin, segYMax, seg->flags, y, splashFloor(xx0), splashFloor(xx1)); } } } #if HAVE_STD_SORT std::sort(allInter, allInter + allInterLen, cmpIntersectFunctor()); #else qsort(allInter, allInterLen, sizeof(SplashIntersect), cmpIntersect); #endif // build the list of y pointers inter = (int *)gmallocn(yMax - yMin + 2, sizeof(int)); i = 0; for (y = yMin; y <= yMax; ++y) { inter[y - yMin] = i; while (i < allInterLen && allInter[i].y <= y) { ++i; } } inter[yMax - yMin + 1] = i; } void SplashXPathScanner::addIntersection(double segYMin, double segYMax, Guint segFlags, int y, int x0, int x1) { if (allInterLen == allInterSize) { allInterSize *= 2; allInter = (SplashIntersect *)greallocn(allInter, allInterSize, sizeof(SplashIntersect)); } allInter[allInterLen].y = y; if (x0 < x1) { allInter[allInterLen].x0 = x0; allInter[allInterLen].x1 = x1; } else { allInter[allInterLen].x0 = x1; allInter[allInterLen].x1 = x0; } if (segYMin <= y && (SplashCoord)y < segYMax && !(segFlags & splashXPathHoriz)) { allInter[allInterLen].count = eo ? 1 : (segFlags & splashXPathFlip) ? 1 : -1; } else { allInter[allInterLen].count = 0; } ++allInterLen; } void SplashXPathScanner::renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { int xx0, xx1, xx, xxMin, xxMax, yy, interEnd; Guchar mask; SplashColorPtr p; memset(aaBuf->getDataPtr(), 0, aaBuf->getRowSize() * aaBuf->getHeight()); xxMin = aaBuf->getWidth(); xxMax = -1; if (yMin <= yMax) { if (splashAASize * y < yMin) { interIdx = inter[0]; } else if (splashAASize * y > yMax) { interIdx = inter[yMax - yMin + 1]; } else { interIdx = inter[splashAASize * y - yMin]; } for (yy = 0; yy < splashAASize; ++yy) { if (splashAASize * y + yy < yMin) { interEnd = inter[0]; } else if (splashAASize * y + yy > yMax) { interEnd = inter[yMax - yMin + 1]; } else { interEnd = inter[splashAASize * y + yy - yMin + 1]; } interCount = 0; while (interIdx < interEnd) { xx0 = allInter[interIdx].x0; xx1 = allInter[interIdx].x1; interCount += allInter[interIdx].count; ++interIdx; while (interIdx < interEnd && (allInter[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { if (allInter[interIdx].x1 > xx1) { xx1 = allInter[interIdx].x1; } interCount += allInter[interIdx].count; ++interIdx; } if (xx0 < 0) { xx0 = 0; } ++xx1; if (xx1 > aaBuf->getWidth()) { xx1 = aaBuf->getWidth(); } // set [xx0, xx1) to 1 if (xx0 < xx1) { xx = xx0; p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); if (xx & 7) { mask = 0xff >> (xx & 7); if ((xx & ~7) == (xx1 & ~7)) { mask &= (Guchar)(0xff00 >> (xx1 & 7)); } *p++ |= mask; xx = (xx & ~7) + 8; } for (; xx + 7 < xx1; xx += 8) { *p++ |= 0xff; } if (xx < xx1) { *p |= (Guchar)(0xff00 >> (xx1 & 7)); } } if (xx0 < xxMin) { xxMin = xx0; } if (xx1 > xxMax) { xxMax = xx1; } } } } *x0 = xxMin / splashAASize; *x1 = (xxMax - 1) / splashAASize; } void SplashXPathScanner::clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y) { int xx0, xx1, xx, yy, interEnd; Guchar mask; SplashColorPtr p; for (yy = 0; yy < splashAASize; ++yy) { xx = *x0 * splashAASize; if (yMin <= yMax) { if (splashAASize * y + yy < yMin) { interIdx = interEnd = inter[0]; } else if (splashAASize * y + yy > yMax) { interIdx = interEnd = inter[yMax - yMin + 1]; } else { interIdx = inter[splashAASize * y + yy - yMin]; if (splashAASize * y + yy > yMax) { interEnd = inter[yMax - yMin + 1]; } else { interEnd = inter[splashAASize * y + yy - yMin + 1]; } } interCount = 0; while (interIdx < interEnd && xx < (*x1 + 1) * splashAASize) { xx0 = allInter[interIdx].x0; xx1 = allInter[interIdx].x1; interCount += allInter[interIdx].count; ++interIdx; while (interIdx < interEnd && (allInter[interIdx].x0 <= xx1 || (eo ? (interCount & 1) : (interCount != 0)))) { if (allInter[interIdx].x1 > xx1) { xx1 = allInter[interIdx].x1; } interCount += allInter[interIdx].count; ++interIdx; } if (xx0 > aaBuf->getWidth()) { xx0 = aaBuf->getWidth(); } // set [xx, xx0) to 0 if (xx < xx0) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); if (xx & 7) { mask = (Guchar)(0xff00 >> (xx & 7)); if ((xx & ~7) == (xx0 & ~7)) { mask |= 0xff >> (xx0 & 7); } *p++ &= mask; xx = (xx & ~7) + 8; } for (; xx + 7 < xx0; xx += 8) { *p++ = 0x00; } if (xx < xx0) { *p &= 0xff >> (xx0 & 7); } } if (xx1 >= xx) { xx = xx1 + 1; } } } xx0 = (*x1 + 1) * splashAASize; // set [xx, xx0) to 0 if (xx < xx0) { p = aaBuf->getDataPtr() + yy * aaBuf->getRowSize() + (xx >> 3); if (xx & 7) { mask = (Guchar)(0xff00 >> (xx & 7)); if ((xx & ~7) == (xx0 & ~7)) { mask &= 0xff >> (xx0 & 7); } *p++ &= mask; xx = (xx & ~7) + 8; } for (; xx + 7 < xx0; xx += 8) { *p++ = 0x00; } if (xx < xx0) { *p &= 0xff >> (xx0 & 7); } } } } xpdf-3.03/splash/SplashXPathScanner.h0000644000076400007640000000573011622305345017074 0ustar dereknderekn//======================================================================== // // SplashXPathScanner.h // //======================================================================== #ifndef SPLASHXPATHSCANNER_H #define SPLASHXPATHSCANNER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" class SplashXPath; class SplashBitmap; struct SplashIntersect; //------------------------------------------------------------------------ // SplashXPathScanner //------------------------------------------------------------------------ class SplashXPathScanner { public: // Create a new SplashXPathScanner object. must be sorted. SplashXPathScanner(SplashXPath *xPathA, GBool eoA, int clipYMin, int clipYMax); ~SplashXPathScanner(); // Return the path's bounding box. void getBBox(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA) { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; } // Return the path's bounding box. void getBBoxAA(int *xMinA, int *yMinA, int *xMaxA, int *yMaxA); // Returns true if at least part of the path was outside the // clipYMin/clipYMax bounds passed to the constructor. GBool hasPartialClip() { return partialClip; } // Return the min/max x values for the span at . void getSpanBounds(int y, int *spanXMin, int *spanXMax); // Returns true if (,) is inside the path. GBool test(int x, int y); // Returns true if the entire span ([,], ) is inside the // path. GBool testSpan(int x0, int x1, int y); // Returns the next span inside the path at . If is // different than the previous call to getNextSpan, this returns the // first span at ; otherwise it returns the next span (relative // to the previous call to getNextSpan). Returns false if there are // no more spans at . GBool getNextSpan(int y, int *x0, int *x1); // Renders one anti-aliased line into . Returns the min and // max x coordinates with non-zero pixels in and . void renderAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); // Clips an anti-aliased line by setting pixels to zero. On entry, // all non-zero pixels are between and . This function // will update and . void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); private: void computeIntersections(); void addIntersection(double segYMin, double segYMax, Guint segFlags, int y, int x0, int x1); SplashXPath *xPath; GBool eo; int xMin, yMin, xMax, yMax; GBool partialClip; SplashIntersect *allInter; // array of intersections int allInterLen; // number of intersections in int allInterSize; // size of the array int *inter; // indexes into for each y value int interY; // current y value - used by getNextSpan int interIdx; // current index into - used by // getNextSpan int interCount; // current EO/NZWN counter - used by // getNextSpan }; #endif xpdf-3.03/splash/SplashClip.h0000644000076400007640000000624011622305345015422 0ustar dereknderekn//======================================================================== // // SplashClip.h // //======================================================================== #ifndef SPLASHCLIP_H #define SPLASHCLIP_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" #include "SplashMath.h" class SplashPath; class SplashXPath; class SplashXPathScanner; class SplashBitmap; //------------------------------------------------------------------------ enum SplashClipResult { splashClipAllInside, splashClipAllOutside, splashClipPartial }; //------------------------------------------------------------------------ // SplashClip //------------------------------------------------------------------------ class SplashClip { public: // Create a clip, for the given rectangle. SplashClip(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, GBool antialiasA); // Copy a clip. SplashClip *copy() { return new SplashClip(this); } ~SplashClip(); // Reset the clip to a rectangle. void resetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); // Intersect the clip with a rectangle. SplashError clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); // Interesect the clip with . SplashError clipToPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness, GBool eo); // Returns true if (,) is inside the clip. GBool test(int x, int y); // Tests a rectangle against the clipping region. Returns one of: // - splashClipAllInside if the entire rectangle is inside the // clipping region, i.e., all pixels in the rectangle are // visible // - splashClipAllOutside if the entire rectangle is outside the // clipping region, i.e., all the pixels in the rectangle are // clipped // - splashClipPartial if the rectangle is part inside and part // outside the clipping region SplashClipResult testRect(int rectXMin, int rectYMin, int rectXMax, int rectYMax); // Similar to testRect, but tests a horizontal span. SplashClipResult testSpan(int spanXMin, int spanXMax, int spanY); // Clips an anti-aliased line by setting pixels to zero. On entry, // all non-zero pixels are between and . This function // will update and . void clipAALine(SplashBitmap *aaBuf, int *x0, int *x1, int y); // Get the rectangle part of the clip region. SplashCoord getXMin() { return xMin; } SplashCoord getXMax() { return xMax; } SplashCoord getYMin() { return yMin; } SplashCoord getYMax() { return yMax; } // Get the rectangle part of the clip region, in integer coordinates. int getXMinI() { return xMinI; } int getXMaxI() { return xMaxI; } int getYMinI() { return yMinI; } int getYMaxI() { return yMaxI; } // Get the number of arbitrary paths used by the clip region. int getNumPaths() { return length; } private: SplashClip(SplashClip *clip); void grow(int nPaths); GBool antialias; SplashCoord xMin, yMin, xMax, yMax; int xMinI, yMinI, xMaxI, yMaxI; SplashXPath **paths; Guchar *flags; SplashXPathScanner **scanners; int length, size; }; #endif xpdf-3.03/splash/SplashT1FontEngine.h0000644000076400007640000000212011622305345016765 0ustar dereknderekn//======================================================================== // // SplashT1FontEngine.h // //======================================================================== #ifndef SPLASHT1FONTENGINE_H #define SPLASHT1FONTENGINE_H #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" class SplashFontFile; class SplashFontFileID; //------------------------------------------------------------------------ // SplashT1FontEngine //------------------------------------------------------------------------ class SplashT1FontEngine { public: static SplashT1FontEngine *init(GBool aaA); ~SplashT1FontEngine(); // Load fonts. SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); private: SplashT1FontEngine(GBool aaA); static int t1libInitCount; GBool aa; friend class SplashT1FontFile; friend class SplashT1Font; }; #endif // HAVE_T1LIB_H #endif xpdf-3.03/splash/Splash.h0000644000076400007640000003242411622305345014615 0ustar dereknderekn//======================================================================== // // Splash.h // //======================================================================== #ifndef SPLASH_H #define SPLASH_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" #include "SplashClip.h" class Splash; class SplashBitmap; struct SplashGlyphBitmap; class SplashState; class SplashPattern; class SplashScreen; class SplashPath; class SplashXPath; class SplashFont; struct SplashPipe; //------------------------------------------------------------------------ // Retrieves the next line of pixels in an image mask. Normally, // fills in * and returns true. If the image stream is // exhausted, returns false. typedef GBool (*SplashImageMaskSource)(void *data, SplashColorPtr pixel); // Retrieves the next line of pixels in an image. Normally, fills in // * and returns true. If the image stream is exhausted, // returns false. typedef GBool (*SplashImageSource)(void *data, SplashColorPtr colorLine, Guchar *alphaLine); //------------------------------------------------------------------------ enum SplashPipeResultColorCtrl { splashPipeResultColorNoAlphaBlendMono, splashPipeResultColorNoAlphaBlendRGB, #if SPLASH_CMYK splashPipeResultColorNoAlphaBlendCMYK, #endif splashPipeResultColorAlphaNoBlendMono, splashPipeResultColorAlphaNoBlendRGB, #if SPLASH_CMYK splashPipeResultColorAlphaNoBlendCMYK, #endif splashPipeResultColorAlphaBlendMono, splashPipeResultColorAlphaBlendRGB #if SPLASH_CMYK , splashPipeResultColorAlphaBlendCMYK #endif }; //------------------------------------------------------------------------ // Splash //------------------------------------------------------------------------ class Splash { public: // Create a new rasterizer object. Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreenParams *screenParams = NULL); Splash(SplashBitmap *bitmapA, GBool vectorAntialiasA, SplashScreen *screenA); ~Splash(); //----- state read SplashCoord *getMatrix(); SplashPattern *getStrokePattern(); SplashPattern *getFillPattern(); SplashScreen *getScreen(); SplashBlendFunc getBlendFunc(); SplashCoord getStrokeAlpha(); SplashCoord getFillAlpha(); SplashCoord getLineWidth(); int getLineCap(); int getLineJoin(); SplashCoord getMiterLimit(); SplashCoord getFlatness(); SplashCoord *getLineDash(); int getLineDashLength(); SplashCoord getLineDashPhase(); GBool getStrokeAdjust(); SplashClip *getClip(); SplashBitmap *getSoftMask(); GBool getInNonIsolatedGroup(); //----- state write void setMatrix(SplashCoord *matrix); void setStrokePattern(SplashPattern *strokeColor); void setFillPattern(SplashPattern *fillColor); void setScreen(SplashScreen *screen); void setBlendFunc(SplashBlendFunc func); void setStrokeAlpha(SplashCoord alpha); void setFillAlpha(SplashCoord alpha); void setLineWidth(SplashCoord lineWidth); void setLineCap(int lineCap); void setLineJoin(int lineJoin); void setMiterLimit(SplashCoord miterLimit); void setFlatness(SplashCoord flatness); // the array will be copied void setLineDash(SplashCoord *lineDash, int lineDashLength, SplashCoord lineDashPhase); void setStrokeAdjust(GBool strokeAdjust); // NB: uses transformed coordinates. void clipResetToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); // NB: uses transformed coordinates. SplashError clipToRect(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1); // NB: uses untransformed coordinates. SplashError clipToPath(SplashPath *path, GBool eo); void setSoftMask(SplashBitmap *softMask); void setInNonIsolatedGroup(SplashBitmap *alpha0BitmapA, int alpha0XA, int alpha0YA); void setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray); void setOverprintMask(Guint overprintMask); //----- state save/restore void saveState(); SplashError restoreState(); //----- drawing operations // Fill the bitmap with . This is not subject to clipping. void clear(SplashColorPtr color, Guchar alpha = 0x00); // Stroke a path using the current stroke pattern. SplashError stroke(SplashPath *path); // Fill a path using the current fill pattern. SplashError fill(SplashPath *path, GBool eo); // Fill a path, XORing with the current fill pattern. SplashError xorFill(SplashPath *path, GBool eo); // Draw a character, using the current fill pattern. SplashError fillChar(SplashCoord x, SplashCoord y, int c, SplashFont *font); // Draw a glyph, using the current fill pattern. This function does // not free any data, i.e., it ignores glyph->freeData. SplashError fillGlyph(SplashCoord x, SplashCoord y, SplashGlyphBitmap *glyph); // Draws an image mask using the fill color. This will read // lines of pixels from , starting with the top line. "1" // pixels will be drawn with the current fill color; "0" pixels are // transparent. The matrix: // [ mat[0] mat[1] 0 ] // [ mat[2] mat[3] 0 ] // [ mat[4] mat[5] 1 ] // maps a unit square to the desired destination for the image, in // PostScript style: // [x' y' 1] = [x y 1] * mat // Note that the Splash y axis points downward, and the image source // is assumed to produce pixels in raster order, starting from the // top line. SplashError fillImageMask(SplashImageMaskSource src, void *srcData, int w, int h, SplashCoord *mat, GBool glyphMode); // Draw an image. This will read lines of pixels from // , starting with the top line. These pixels are assumed to // be in the source mode, . If is true, the // alpha values returned by are used; otherwise they are // ignored. The following combinations of source and target modes // are supported: // source target // ------ ------ // Mono1 Mono1 // Mono8 Mono1 -- with dithering // Mono8 Mono8 // RGB8 RGB8 // BGR8 BGR8 // CMYK8 CMYK8 // The matrix behaves as for fillImageMask. SplashError drawImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, GBool srcAlpha, int w, int h, SplashCoord *mat); // Composite a rectangular region from onto this Splash // object. SplashError composite(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h, GBool noClip, GBool nonIsolated); // Composite this Splash object onto a background color. The // background alpha is assumed to be 1. void compositeBackground(SplashColorPtr color); // Copy a rectangular region from onto the bitmap belonging to // this Splash object. The destination alpha values are all set to // zero. SplashError blitTransparent(SplashBitmap *src, int xSrc, int ySrc, int xDest, int yDest, int w, int h); //----- misc // Construct a path for a stroke, given the path to be stroked and // the line width . All other stroke parameters are taken from // the current state. If is true, this function will // first flatten the path and handle the linedash. SplashPath *makeStrokePath(SplashPath *path, SplashCoord w, GBool flatten = gTrue); // Return the associated bitmap. SplashBitmap *getBitmap() { return bitmap; } // Set the minimum line width. void setMinLineWidth(SplashCoord w) { minLineWidth = w; } // Get a bounding box which includes all modifications since the // last call to clearModRegion. void getModRegion(int *xMin, int *yMin, int *xMax, int *yMax) { *xMin = modXMin; *yMin = modYMin; *xMax = modXMax; *yMax = modYMax; } // Clear the modified region bounding box. void clearModRegion(); // Get clipping status for the last drawing operation subject to // clipping. SplashClipResult getClipRes() { return opClipRes; } // Toggle debug mode on or off. void setDebugMode(GBool debugModeA) { debugMode = debugModeA; } #if 1 //~tmp: turn off anti-aliasing temporarily void setInShading(GBool sh) { inShading = sh; } #endif private: void pipeInit(SplashPipe *pipe, int x, int y, SplashPattern *pattern, SplashColorPtr cSrc, Guchar aInput, GBool usesShape, GBool nonIsolatedGroup); void pipeRun(SplashPipe *pipe); void pipeRunSimpleMono1(SplashPipe *pipe); void pipeRunSimpleMono8(SplashPipe *pipe); void pipeRunSimpleRGB8(SplashPipe *pipe); void pipeRunSimpleBGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunSimpleCMYK8(SplashPipe *pipe); #endif void pipeRunAAMono1(SplashPipe *pipe); void pipeRunAAMono8(SplashPipe *pipe); void pipeRunAARGB8(SplashPipe *pipe); void pipeRunAABGR8(SplashPipe *pipe); #if SPLASH_CMYK void pipeRunAACMYK8(SplashPipe *pipe); #endif void pipeSetXY(SplashPipe *pipe, int x, int y); void pipeIncX(SplashPipe *pipe); void drawPixel(SplashPipe *pipe, int x, int y, GBool noClip); void drawAAPixelInit(); void drawAAPixel(SplashPipe *pipe, int x, int y); void drawSpan(SplashPipe *pipe, int x0, int x1, int y, GBool noClip); void drawAALine(SplashPipe *pipe, int x0, int x1, int y); void transform(SplashCoord *matrix, SplashCoord xi, SplashCoord yi, SplashCoord *xo, SplashCoord *yo); void updateModX(int x); void updateModY(int y); void strokeNarrow(SplashPath *path); void strokeWide(SplashPath *path, SplashCoord w); SplashPath *flattenPath(SplashPath *path, SplashCoord *matrix, SplashCoord flatness); void flattenCurve(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3, SplashCoord *matrix, SplashCoord flatness2, SplashPath *fPath); SplashPath *makeDashedPath(SplashPath *xPath); SplashError fillWithPattern(SplashPath *path, GBool eo, SplashPattern *pattern, SplashCoord alpha); GBool pathAllOutside(SplashPath *path); SplashError fillGlyph2(int x0, int y0, SplashGlyphBitmap *glyph); void arbitraryTransformMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, SplashCoord *mat, GBool glyphMode); SplashBitmap *scaleMask(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight); void scaleMaskYdXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleMaskYdXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleMaskYuXd(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleMaskYuXu(SplashImageMaskSource src, void *srcData, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void blitMask(SplashBitmap *src, int xDest, int yDest, SplashClipResult clipRes); void arbitraryTransformImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, SplashCoord *mat); SplashBitmap *scaleImage(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight); void scaleImageYdXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleImageYdXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleImageYuXd(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void scaleImageYuXu(SplashImageSource src, void *srcData, SplashColorMode srcMode, int nComps, GBool srcAlpha, int srcWidth, int srcHeight, int scaledWidth, int scaledHeight, SplashBitmap *dest); void vertFlipImage(SplashBitmap *img, int width, int height, int nComps); void blitImage(SplashBitmap *src, GBool srcAlpha, int xDest, int yDest, SplashClipResult clipRes); void blitImageClipped(SplashBitmap *src, GBool srcAlpha, int xSrc, int ySrc, int xDest, int yDest, int w, int h); void dumpPath(SplashPath *path); void dumpXPath(SplashXPath *path); static SplashPipeResultColorCtrl pipeResultColorNoAlphaBlend[]; static SplashPipeResultColorCtrl pipeResultColorAlphaNoBlend[]; static SplashPipeResultColorCtrl pipeResultColorAlphaBlend[]; static int pipeNonIsoGroupCorrection[]; SplashBitmap *bitmap; SplashState *state; SplashBitmap *aaBuf; int aaBufY; SplashBitmap *alpha0Bitmap; // for non-isolated groups, this is the // bitmap containing the alpha0 values int alpha0X, alpha0Y; // offset within alpha0Bitmap Guchar aaGamma[splashAASize * splashAASize + 1]; SplashCoord minLineWidth; int modXMin, modYMin, modXMax, modYMax; SplashClipResult opClipRes; GBool vectorAntialias; GBool inShading; GBool debugMode; }; #endif xpdf-3.03/splash/SplashFTFontFile.h0000644000076400007640000000360011622305345016470 0ustar dereknderekn//======================================================================== // // SplashFTFontFile.h // //======================================================================== #ifndef SPLASHFTFONTFILE_H #define SPLASHFTFONTFILE_H #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include FT_FREETYPE_H #include "SplashFontFile.h" class SplashFontFileID; class SplashFTFontEngine; //------------------------------------------------------------------------ // SplashFTFontFile //------------------------------------------------------------------------ class SplashFTFontFile: public SplashFontFile { public: static SplashFontFile *loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, const char **encA); static SplashFontFile *loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, int *codeToGIDA, int codeToGIDLenA); static SplashFontFile *loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, int fontNum, GBool deleteFileA, int *codeToGIDA, int codeToGIDLenA); virtual ~SplashFTFontFile(); // Create a new SplashFTFont, i.e., a scaled instance of this font // file. virtual SplashFont *makeFont(SplashCoord *mat, SplashCoord *textMat); private: SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, FT_Face faceA, int *codeToGIDA, int codeToGIDLenA, GBool trueTypeA, GBool type1A); SplashFTFontEngine *engine; FT_Face face; int *codeToGID; int codeToGIDLen; GBool trueType; GBool type1; friend class SplashFTFont; }; #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #endif xpdf-3.03/splash/SplashPath.cc0000644000076400007640000001062711622305345015571 0ustar dereknderekn//======================================================================== // // SplashPath.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "SplashErrorCodes.h" #include "SplashPath.h" //------------------------------------------------------------------------ // SplashPath //------------------------------------------------------------------------ // A path can be in three possible states: // // 1. no current point -- zero or more finished subpaths // [curSubpath == length] // // 2. one point in subpath // [curSubpath == length - 1] // // 3. open subpath with two or more points // [curSubpath < length - 1] SplashPath::SplashPath() { pts = NULL; flags = NULL; length = size = 0; curSubpath = 0; hints = NULL; hintsLength = hintsSize = 0; } SplashPath::SplashPath(SplashPath *path) { length = path->length; size = path->size; pts = (SplashPathPoint *)gmallocn(size, sizeof(SplashPathPoint)); flags = (Guchar *)gmallocn(size, sizeof(Guchar)); memcpy(pts, path->pts, length * sizeof(SplashPathPoint)); memcpy(flags, path->flags, length * sizeof(Guchar)); curSubpath = path->curSubpath; if (path->hints) { hintsLength = hintsSize = path->hintsLength; hints = (SplashPathHint *)gmallocn(hintsSize, sizeof(SplashPathHint)); memcpy(hints, path->hints, hintsLength * sizeof(SplashPathHint)); } else { hints = NULL; } } SplashPath::~SplashPath() { gfree(pts); gfree(flags); gfree(hints); } // Add space for more points. void SplashPath::grow(int nPts) { if (length + nPts > size) { if (size == 0) { size = 32; } while (size < length + nPts) { size *= 2; } pts = (SplashPathPoint *)greallocn(pts, size, sizeof(SplashPathPoint)); flags = (Guchar *)greallocn(flags, size, sizeof(Guchar)); } } void SplashPath::append(SplashPath *path) { int i; curSubpath = length + path->curSubpath; grow(path->length); for (i = 0; i < path->length; ++i) { pts[length] = path->pts[i]; flags[length] = path->flags[i]; ++length; } } SplashError SplashPath::moveTo(SplashCoord x, SplashCoord y) { if (onePointSubpath()) { return splashErrBogusPath; } grow(1); pts[length].x = x; pts[length].y = y; flags[length] = splashPathFirst | splashPathLast; curSubpath = length++; return splashOk; } SplashError SplashPath::lineTo(SplashCoord x, SplashCoord y) { if (noCurrentPoint()) { return splashErrNoCurPt; } flags[length-1] &= ~splashPathLast; grow(1); pts[length].x = x; pts[length].y = y; flags[length] = splashPathLast; ++length; return splashOk; } SplashError SplashPath::curveTo(SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3) { if (noCurrentPoint()) { return splashErrNoCurPt; } flags[length-1] &= ~splashPathLast; grow(3); pts[length].x = x1; pts[length].y = y1; flags[length] = splashPathCurve; ++length; pts[length].x = x2; pts[length].y = y2; flags[length] = splashPathCurve; ++length; pts[length].x = x3; pts[length].y = y3; flags[length] = splashPathLast; ++length; return splashOk; } SplashError SplashPath::close(GBool force) { if (noCurrentPoint()) { return splashErrNoCurPt; } if (force || curSubpath == length - 1 || pts[length - 1].x != pts[curSubpath].x || pts[length - 1].y != pts[curSubpath].y) { lineTo(pts[curSubpath].x, pts[curSubpath].y); } flags[curSubpath] |= splashPathClosed; flags[length - 1] |= splashPathClosed; curSubpath = length; return splashOk; } void SplashPath::addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt) { if (hintsLength == hintsSize) { hintsSize = hintsLength ? 2 * hintsLength : 8; hints = (SplashPathHint *)greallocn(hints, hintsSize, sizeof(SplashPathHint)); } hints[hintsLength].ctrl0 = ctrl0; hints[hintsLength].ctrl1 = ctrl1; hints[hintsLength].firstPt = firstPt; hints[hintsLength].lastPt = lastPt; ++hintsLength; } void SplashPath::offset(SplashCoord dx, SplashCoord dy) { int i; for (i = 0; i < length; ++i) { pts[i].x += dx; pts[i].y += dy; } } GBool SplashPath::getCurPt(SplashCoord *x, SplashCoord *y) { if (noCurrentPoint()) { return gFalse; } *x = pts[length - 1].x; *y = pts[length - 1].y; return gTrue; } xpdf-3.03/splash/SplashPattern.h0000644000076400007640000000257211622305345016154 0ustar dereknderekn//======================================================================== // // SplashPattern.h // //======================================================================== #ifndef SPLASHPATTERN_H #define SPLASHPATTERN_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" class SplashScreen; //------------------------------------------------------------------------ // SplashPattern //------------------------------------------------------------------------ class SplashPattern { public: SplashPattern(); virtual SplashPattern *copy() = 0; virtual ~SplashPattern(); // Return the color value for a specific pixel. virtual void getColor(int x, int y, SplashColorPtr c) = 0; // Returns true if this pattern object will return the same color // value for all pixels. virtual GBool isStatic() = 0; private: }; //------------------------------------------------------------------------ // SplashSolidColor //------------------------------------------------------------------------ class SplashSolidColor: public SplashPattern { public: SplashSolidColor(SplashColorPtr colorA); virtual SplashPattern *copy() { return new SplashSolidColor(color); } virtual ~SplashSolidColor(); virtual void getColor(int x, int y, SplashColorPtr c); virtual GBool isStatic() { return gTrue; } private: SplashColor color; }; #endif xpdf-3.03/splash/SplashPattern.cc0000644000076400007640000000172211622305345016306 0ustar dereknderekn//======================================================================== // // SplashPattern.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "SplashMath.h" #include "SplashScreen.h" #include "SplashPattern.h" //------------------------------------------------------------------------ // SplashPattern //------------------------------------------------------------------------ SplashPattern::SplashPattern() { } SplashPattern::~SplashPattern() { } //------------------------------------------------------------------------ // SplashSolidColor //------------------------------------------------------------------------ SplashSolidColor::SplashSolidColor(SplashColorPtr colorA) { splashColorCopy(color, colorA); } SplashSolidColor::~SplashSolidColor() { } void SplashSolidColor::getColor(int x, int y, SplashColorPtr c) { splashColorCopy(c, color); } xpdf-3.03/splash/SplashT1FontEngine.cc0000644000076400007640000000564711622305345017144 0ustar dereknderekn//======================================================================== // // SplashT1FontEngine.cc // //======================================================================== #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #ifndef WIN32 # include #endif #include #include "GString.h" #include "gfile.h" #include "FoFiType1C.h" #include "SplashT1FontFile.h" #include "SplashT1FontEngine.h" #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #endif //------------------------------------------------------------------------ int SplashT1FontEngine::t1libInitCount = 0; //------------------------------------------------------------------------ static void fileWrite(void *stream, const char *data, int len) { fwrite(data, 1, len, (FILE *)stream); } //------------------------------------------------------------------------ // SplashT1FontEngine //------------------------------------------------------------------------ SplashT1FontEngine::SplashT1FontEngine(GBool aaA) { aa = aaA; } SplashT1FontEngine *SplashT1FontEngine::init(GBool aaA) { // grayVals[i] = round(i * 255 / 16) static unsigned long grayVals[17] = { 0, 16, 32, 48, 64, 80, 96, 112, 128, 143, 159, 175, 191, 207, 223, 239, 255 }; //~ for multithreading: need a mutex here if (t1libInitCount == 0) { T1_SetBitmapPad(8); if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | T1_NO_AFM)) { return NULL; } if (aaA) { T1_AASetBitsPerPixel(8); T1_AASetLevel(T1_AA_HIGH); T1_AAHSetGrayValues(grayVals); } else { T1_AANSetGrayValues(0, 1); } } ++t1libInitCount; return new SplashT1FontEngine(aaA); } SplashT1FontEngine::~SplashT1FontEngine() { //~ for multithreading: need a mutex here if (--t1libInitCount == 0) { T1_CloseLib(); } } SplashFontFile *SplashT1FontEngine::loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { return SplashT1FontFile::loadType1Font(this, idA, fileName, deleteFile, enc); } SplashFontFile *SplashT1FontEngine::loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { FoFiType1C *ff; GString *tmpFileName; FILE *tmpFile; SplashFontFile *ret; if (!(ff = FoFiType1C::load(fileName))) { return NULL; } tmpFileName = NULL; if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { delete ff; return NULL; } ff->convertToType1(NULL, NULL, gTrue, &fileWrite, tmpFile); delete ff; fclose(tmpFile); ret = SplashT1FontFile::loadType1Font(this, idA, tmpFileName->getCString(), gTrue, enc); if (ret) { if (deleteFile) { unlink(fileName); } } else { unlink(tmpFileName->getCString()); } delete tmpFileName; return ret; } #endif // HAVE_T1LIB_H xpdf-3.03/splash/SplashFont.cc0000644000076400007640000001074311622305345015602 0ustar dereknderekn//======================================================================== // // SplashFont.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" #include "SplashFontFile.h" #include "SplashFont.h" //------------------------------------------------------------------------ // font cache size parameters #define splashFontCacheAssoc 8 #define splashFontCacheMaxSets 8 #define splashFontCacheSize (128*1024) //------------------------------------------------------------------------ struct SplashFontCacheTag { int c; short xFrac, yFrac; // x and y fractions int mru; // valid bit (0x80000000) and MRU index int x, y, w, h; // offset and size of glyph }; //------------------------------------------------------------------------ // SplashFont //------------------------------------------------------------------------ SplashFont::SplashFont(SplashFontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA, GBool aaA) { fontFile = fontFileA; fontFile->incRefCnt(); mat[0] = matA[0]; mat[1] = matA[1]; mat[2] = matA[2]; mat[3] = matA[3]; textMat[0] = textMatA[0]; textMat[1] = textMatA[1]; textMat[2] = textMatA[2]; textMat[3] = textMatA[3]; aa = aaA; cache = NULL; cacheTags = NULL; xMin = yMin = xMax = yMax = 0; } void SplashFont::initCache() { int i; // this should be (max - min + 1), but we add some padding to // deal with rounding errors glyphW = xMax - xMin + 3; glyphH = yMax - yMin + 3; if (aa) { glyphSize = glyphW * glyphH; } else { glyphSize = ((glyphW + 7) >> 3) * glyphH; } // set up the glyph pixmap cache cacheAssoc = splashFontCacheAssoc; for (cacheSets = splashFontCacheMaxSets; cacheSets > 1 && cacheSets * cacheAssoc * glyphSize > splashFontCacheSize; cacheSets >>= 1) ; cache = (Guchar *)gmallocn(cacheSets * cacheAssoc, glyphSize); cacheTags = (SplashFontCacheTag *)gmallocn(cacheSets * cacheAssoc, sizeof(SplashFontCacheTag)); for (i = 0; i < cacheSets * cacheAssoc; ++i) { cacheTags[i].mru = i & (cacheAssoc - 1); } } SplashFont::~SplashFont() { fontFile->decRefCnt(); if (cache) { gfree(cache); } if (cacheTags) { gfree(cacheTags); } } GBool SplashFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { SplashGlyphBitmap bitmap2; int size; Guchar *p; int i, j, k; // no fractional coordinates for large glyphs or non-anti-aliased // glyphs if (!aa || glyphH > 50) { xFrac = yFrac = 0; } // check the cache i = (c & (cacheSets - 1)) * cacheAssoc; for (j = 0; j < cacheAssoc; ++j) { if ((cacheTags[i+j].mru & 0x80000000) && cacheTags[i+j].c == c && (int)cacheTags[i+j].xFrac == xFrac && (int)cacheTags[i+j].yFrac == yFrac) { bitmap->x = cacheTags[i+j].x; bitmap->y = cacheTags[i+j].y; bitmap->w = cacheTags[i+j].w; bitmap->h = cacheTags[i+j].h; for (k = 0; k < cacheAssoc; ++k) { if (k != j && (cacheTags[i+k].mru & 0x7fffffff) < (cacheTags[i+j].mru & 0x7fffffff)) { ++cacheTags[i+k].mru; } } cacheTags[i+j].mru = 0x80000000; bitmap->aa = aa; bitmap->data = cache + (i+j) * glyphSize; bitmap->freeData = gFalse; return gTrue; } } // generate the glyph bitmap if (!makeGlyph(c, xFrac, yFrac, &bitmap2)) { return gFalse; } // if the glyph doesn't fit in the bounding box, return a temporary // uncached bitmap if (bitmap2.w > glyphW || bitmap2.h > glyphH) { *bitmap = bitmap2; return gTrue; } // insert glyph pixmap in cache if (aa) { size = bitmap2.w * bitmap2.h; } else { size = ((bitmap2.w + 7) >> 3) * bitmap2.h; } p = NULL; // make gcc happy for (j = 0; j < cacheAssoc; ++j) { if ((cacheTags[i+j].mru & 0x7fffffff) == cacheAssoc - 1) { cacheTags[i+j].mru = 0x80000000; cacheTags[i+j].c = c; cacheTags[i+j].xFrac = (short)xFrac; cacheTags[i+j].yFrac = (short)yFrac; cacheTags[i+j].x = bitmap2.x; cacheTags[i+j].y = bitmap2.y; cacheTags[i+j].w = bitmap2.w; cacheTags[i+j].h = bitmap2.h; p = cache + (i+j) * glyphSize; memcpy(p, bitmap2.data, size); } else { ++cacheTags[i+j].mru; } } *bitmap = bitmap2; bitmap->data = p; bitmap->freeData = gFalse; if (bitmap2.freeData) { gfree(bitmap2.data); } return gTrue; } xpdf-3.03/splash/SplashFontFileID.h0000644000076400007640000000120411622305345016451 0ustar dereknderekn//======================================================================== // // SplashFontFileID.h // //======================================================================== #ifndef SPLASHFONTFILEID_H #define SPLASHFONTFILEID_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" //------------------------------------------------------------------------ // SplashFontFileID //------------------------------------------------------------------------ class SplashFontFileID { public: SplashFontFileID(); virtual ~SplashFontFileID(); virtual GBool matches(SplashFontFileID *id) = 0; }; #endif xpdf-3.03/splash/SplashState.cc0000644000076400007640000001365611622305345015762 0ustar dereknderekn//======================================================================== // // SplashState.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "gmem.h" #include "SplashPattern.h" #include "SplashScreen.h" #include "SplashClip.h" #include "SplashBitmap.h" #include "SplashState.h" //------------------------------------------------------------------------ // SplashState //------------------------------------------------------------------------ // number of components in each color mode int splashColorModeNComps[] = { 1, 1, 3, 3 #if SPLASH_CMYK , 4 #endif }; SplashState::SplashState(int width, int height, GBool vectorAntialias, SplashScreenParams *screenParams) { SplashColor color; int i; matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 1; matrix[4] = 0; matrix[5] = 0; memset(&color, 0, sizeof(SplashColor)); strokePattern = new SplashSolidColor(color); fillPattern = new SplashSolidColor(color); screen = new SplashScreen(screenParams); blendFunc = NULL; strokeAlpha = 1; fillAlpha = 1; lineWidth = 0; lineCap = splashLineCapButt; lineJoin = splashLineJoinMiter; miterLimit = 10; flatness = 1; lineDash = NULL; lineDashLength = 0; lineDashPhase = 0; strokeAdjust = gFalse; clip = new SplashClip(0, 0, width, height, vectorAntialias); softMask = NULL; deleteSoftMask = gFalse; inNonIsolatedGroup = gFalse; for (i = 0; i < 256; ++i) { rgbTransferR[i] = (Guchar)i; rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; } overprintMask = 0xffffffff; next = NULL; } SplashState::SplashState(int width, int height, GBool vectorAntialias, SplashScreen *screenA) { SplashColor color; int i; matrix[0] = 1; matrix[1] = 0; matrix[2] = 0; matrix[3] = 1; matrix[4] = 0; matrix[5] = 0; memset(&color, 0, sizeof(SplashColor)); strokePattern = new SplashSolidColor(color); fillPattern = new SplashSolidColor(color); screen = screenA->copy(); blendFunc = NULL; strokeAlpha = 1; fillAlpha = 1; lineWidth = 0; lineCap = splashLineCapButt; lineJoin = splashLineJoinMiter; miterLimit = 10; flatness = 1; lineDash = NULL; lineDashLength = 0; lineDashPhase = 0; strokeAdjust = gFalse; clip = new SplashClip(0, 0, width, height, vectorAntialias); softMask = NULL; deleteSoftMask = gFalse; inNonIsolatedGroup = gFalse; for (i = 0; i < 256; ++i) { rgbTransferR[i] = (Guchar)i; rgbTransferG[i] = (Guchar)i; rgbTransferB[i] = (Guchar)i; grayTransfer[i] = (Guchar)i; cmykTransferC[i] = (Guchar)i; cmykTransferM[i] = (Guchar)i; cmykTransferY[i] = (Guchar)i; cmykTransferK[i] = (Guchar)i; } overprintMask = 0xffffffff; next = NULL; } SplashState::SplashState(SplashState *state) { memcpy(matrix, state->matrix, 6 * sizeof(SplashCoord)); strokePattern = state->strokePattern->copy(); fillPattern = state->fillPattern->copy(); screen = state->screen->copy(); blendFunc = state->blendFunc; strokeAlpha = state->strokeAlpha; fillAlpha = state->fillAlpha; lineWidth = state->lineWidth; lineCap = state->lineCap; lineJoin = state->lineJoin; miterLimit = state->miterLimit; flatness = state->flatness; if (state->lineDash) { lineDashLength = state->lineDashLength; lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); memcpy(lineDash, state->lineDash, lineDashLength * sizeof(SplashCoord)); } else { lineDash = NULL; lineDashLength = 0; } lineDashPhase = state->lineDashPhase; strokeAdjust = state->strokeAdjust; clip = state->clip->copy(); softMask = state->softMask; deleteSoftMask = gFalse; inNonIsolatedGroup = state->inNonIsolatedGroup; memcpy(rgbTransferR, state->rgbTransferR, 256); memcpy(rgbTransferG, state->rgbTransferG, 256); memcpy(rgbTransferB, state->rgbTransferB, 256); memcpy(grayTransfer, state->grayTransfer, 256); memcpy(cmykTransferC, state->cmykTransferC, 256); memcpy(cmykTransferM, state->cmykTransferM, 256); memcpy(cmykTransferY, state->cmykTransferY, 256); memcpy(cmykTransferK, state->cmykTransferK, 256); overprintMask = state->overprintMask; next = NULL; } SplashState::~SplashState() { delete strokePattern; delete fillPattern; delete screen; gfree(lineDash); delete clip; if (deleteSoftMask && softMask) { delete softMask; } } void SplashState::setStrokePattern(SplashPattern *strokePatternA) { delete strokePattern; strokePattern = strokePatternA; } void SplashState::setFillPattern(SplashPattern *fillPatternA) { delete fillPattern; fillPattern = fillPatternA; } void SplashState::setScreen(SplashScreen *screenA) { delete screen; screen = screenA; } void SplashState::setLineDash(SplashCoord *lineDashA, int lineDashLengthA, SplashCoord lineDashPhaseA) { gfree(lineDash); lineDashLength = lineDashLengthA; if (lineDashLength > 0) { lineDash = (SplashCoord *)gmallocn(lineDashLength, sizeof(SplashCoord)); memcpy(lineDash, lineDashA, lineDashLength * sizeof(SplashCoord)); } else { lineDash = NULL; } lineDashPhase = lineDashPhaseA; } void SplashState::setSoftMask(SplashBitmap *softMaskA) { if (deleteSoftMask) { delete softMask; } softMask = softMaskA; deleteSoftMask = gTrue; } void SplashState::setTransfer(Guchar *red, Guchar *green, Guchar *blue, Guchar *gray) { int i; memcpy(rgbTransferR, red, 256); memcpy(rgbTransferG, green, 256); memcpy(rgbTransferB, blue, 256); memcpy(grayTransfer, gray, 256); for (i = 0; i < 256; ++i) { cmykTransferC[i] = 255 - rgbTransferR[255 - i]; cmykTransferM[i] = 255 - rgbTransferG[255 - i]; cmykTransferY[i] = 255 - rgbTransferB[255 - i]; cmykTransferK[i] = 255 - grayTransfer[255 - i]; } } xpdf-3.03/splash/SplashGlyphBitmap.h0000644000076400007640000000131311622305345016747 0ustar dereknderekn//======================================================================== // // SplashGlyphBitmap.h // //======================================================================== #ifndef SPLASHGLYPHBITMAP_H #define SPLASHGLYPHBITMAP_H #include #include "gtypes.h" //------------------------------------------------------------------------ // SplashGlyphBitmap //------------------------------------------------------------------------ struct SplashGlyphBitmap { int x, y, w, h; // offset and size of glyph GBool aa; // anti-aliased: true means 8-bit alpha // bitmap; false means 1-bit Guchar *data; // bitmap data GBool freeData; // true if data memory should be freed }; #endif xpdf-3.03/splash/SplashBitmap.cc0000644000076400007640000001074511622305345016112 0ustar dereknderekn//======================================================================== // // SplashBitmap.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "SplashErrorCodes.h" #include "SplashBitmap.h" //------------------------------------------------------------------------ // SplashBitmap //------------------------------------------------------------------------ SplashBitmap::SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, GBool topDown) { width = widthA; height = heightA; mode = modeA; switch (mode) { case splashModeMono1: if (width > 0) { rowSize = (width + 7) >> 3; } else { rowSize = -1; } break; case splashModeMono8: if (width > 0) { rowSize = width; } else { rowSize = -1; } break; case splashModeRGB8: case splashModeBGR8: if (width > 0 && width <= INT_MAX / 3) { rowSize = width * 3; } else { rowSize = -1; } break; #if SPLASH_CMYK case splashModeCMYK8: if (width > 0 && width <= INT_MAX / 4) { rowSize = width * 4; } else { rowSize = -1; } break; #endif } if (rowSize > 0) { rowSize += rowPad - 1; rowSize -= rowSize % rowPad; } data = (SplashColorPtr)gmallocn(height, rowSize); if (!topDown) { data += (height - 1) * rowSize; rowSize = -rowSize; } if (alphaA) { alpha = (Guchar *)gmallocn(width, height); } else { alpha = NULL; } } SplashBitmap::~SplashBitmap() { if (data) { if (rowSize < 0) { gfree(data + (height - 1) * rowSize); } else { gfree(data); } } gfree(alpha); } SplashError SplashBitmap::writePNMFile(char *fileName) { FILE *f; SplashError err; if (!(f = fopen(fileName, "wb"))) { return splashErrOpenFile; } err = writePNMFile(f); fclose(f); return err; } SplashError SplashBitmap::writePNMFile(FILE *f) { SplashColorPtr row, p; int x, y; switch (mode) { case splashModeMono1: fprintf(f, "P4\n%d %d\n", width, height); row = data; for (y = 0; y < height; ++y) { p = row; for (x = 0; x < width; x += 8) { fputc(*p ^ 0xff, f); ++p; } row += rowSize; } break; case splashModeMono8: fprintf(f, "P5\n%d %d\n255\n", width, height); row = data; for (y = 0; y < height; ++y) { fwrite(row, 1, width, f); row += rowSize; } break; case splashModeRGB8: fprintf(f, "P6\n%d %d\n255\n", width, height); row = data; for (y = 0; y < height; ++y) { fwrite(row, 1, 3 * width, f); row += rowSize; } break; case splashModeBGR8: fprintf(f, "P6\n%d %d\n255\n", width, height); row = data; for (y = 0; y < height; ++y) { p = row; for (x = 0; x < width; ++x) { fputc(splashBGR8R(p), f); fputc(splashBGR8G(p), f); fputc(splashBGR8B(p), f); p += 3; } row += rowSize; } break; #if SPLASH_CMYK case splashModeCMYK8: // PNM doesn't support CMYK break; #endif } return splashOk; } SplashError SplashBitmap::writeAlphaPGMFile(char *fileName) { FILE *f; if (!alpha) { return splashErrModeMismatch; } if (!(f = fopen(fileName, "wb"))) { return splashErrOpenFile; } fprintf(f, "P5\n%d %d\n255\n", width, height); fwrite(alpha, 1, width * height, f); fclose(f); return splashOk; } void SplashBitmap::getPixel(int x, int y, SplashColorPtr pixel) { SplashColorPtr p; if (y < 0 || y >= height || x < 0 || x >= width) { return; } switch (mode) { case splashModeMono1: p = &data[y * rowSize + (x >> 3)]; pixel[0] = (p[0] & (0x80 >> (x & 7))) ? 0xff : 0x00; break; case splashModeMono8: p = &data[y * rowSize + x]; pixel[0] = p[0]; break; case splashModeRGB8: p = &data[y * rowSize + 3 * x]; pixel[0] = p[0]; pixel[1] = p[1]; pixel[2] = p[2]; break; case splashModeBGR8: p = &data[y * rowSize + 3 * x]; pixel[0] = p[2]; pixel[1] = p[1]; pixel[2] = p[0]; break; #if SPLASH_CMYK case splashModeCMYK8: p = &data[y * rowSize + 4 * x]; pixel[0] = p[0]; pixel[1] = p[1]; pixel[2] = p[2]; pixel[3] = p[3]; break; #endif } } Guchar SplashBitmap::getAlpha(int x, int y) { return alpha[y * width + x]; } SplashColorPtr SplashBitmap::takeData() { SplashColorPtr data2; data2 = data; data = NULL; return data2; } xpdf-3.03/splash/SplashFTFontFile.cc0000644000076400007640000000566411622305345016642 0ustar dereknderekn//======================================================================== // // SplashFTFontFile.cc // //======================================================================== #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "gmem.h" #include "SplashFTFontEngine.h" #include "SplashFTFont.h" #include "SplashFTFontFile.h" //------------------------------------------------------------------------ // SplashFTFontFile //------------------------------------------------------------------------ SplashFontFile *SplashFTFontFile::loadType1Font(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, const char **encA) { FT_Face faceA; int *codeToGIDA; const char *name; int i; if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { return NULL; } codeToGIDA = (int *)gmallocn(256, sizeof(int)); for (i = 0; i < 256; ++i) { codeToGIDA[i] = 0; if ((name = encA[i])) { codeToGIDA[i] = (int)FT_Get_Name_Index(faceA, (char *)name); } } return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, faceA, codeToGIDA, 256, gFalse, gTrue); } SplashFontFile *SplashFTFontFile::loadCIDFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, int *codeToGIDA, int codeToGIDLenA) { FT_Face faceA; if (FT_New_Face(engineA->lib, fileNameA, 0, &faceA)) { return NULL; } return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, faceA, codeToGIDA, codeToGIDLenA, gFalse, gFalse); } SplashFontFile *SplashFTFontFile::loadTrueTypeFont(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, int fontNum, GBool deleteFileA, int *codeToGIDA, int codeToGIDLenA) { FT_Face faceA; if (FT_New_Face(engineA->lib, fileNameA, fontNum, &faceA)) { return NULL; } return new SplashFTFontFile(engineA, idA, fileNameA, deleteFileA, faceA, codeToGIDA, codeToGIDLenA, gTrue, gFalse); } SplashFTFontFile::SplashFTFontFile(SplashFTFontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, FT_Face faceA, int *codeToGIDA, int codeToGIDLenA, GBool trueTypeA, GBool type1A): SplashFontFile(idA, fileNameA, deleteFileA) { engine = engineA; face = faceA; codeToGID = codeToGIDA; codeToGIDLen = codeToGIDLenA; trueType = trueTypeA; type1 = type1A; } SplashFTFontFile::~SplashFTFontFile() { if (face) { FT_Done_Face(face); } if (codeToGID) { gfree(codeToGID); } } SplashFont *SplashFTFontFile::makeFont(SplashCoord *mat, SplashCoord *textMat) { SplashFont *font; font = new SplashFTFont(this, mat, textMat); font->initCache(); return font; } #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H xpdf-3.03/splash/SplashMath.h0000644000076400007640000001274411622305345015432 0ustar dereknderekn//======================================================================== // // SplashMath.h // //======================================================================== #ifndef SPLASHMATH_H #define SPLASHMATH_H #include #if USE_FIXEDPONT #include "FixedPoint.h" #else #include #endif #include "SplashTypes.h" static inline SplashCoord splashAbs(SplashCoord x) { #if USE_FIXEDPOINT return FixedPoint::abs(x); #else return fabs(x); #endif } static inline int splashFloor(SplashCoord x) { #if USE_FIXEDPOINT return FixedPoint::floor(x); #else #if __GNUC__ && __i386__ // floor() and (int)() are implemented separately, which results // in changing the FPCW multiple times - so we optimize it with // some inline assembly Gushort oldCW, newCW, t; int result; __asm__ volatile("fldl %4\n" "fnstcw %0\n" "movw %0, %3\n" "andw $0xf3ff, %3\n" "orw $0x0400, %3\n" "movw %3, %1\n" // round down "fldcw %1\n" "fistpl %2\n" "fldcw %0\n" : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) : "m" (x)); return result; #elif defined(WIN32) && defined(_M_IX86) // floor() and (int)() are implemented separately, which results // in changing the FPCW multiple times - so we optimize it with // some inline assembly Gushort oldCW, newCW; int result; __asm fld QWORD PTR x __asm fnstcw WORD PTR oldCW __asm mov ax, WORD PTR oldCW __asm and ax, 0xf3ff __asm or ax, 0x0400 __asm mov WORD PTR newCW, ax // round down __asm fldcw WORD PTR newCW __asm fistp DWORD PTR result __asm fldcw WORD PTR oldCW return result; #else return (int)floor(x); #endif #endif } static inline int splashCeil(SplashCoord x) { #if USE_FIXEDPOINT return FixedPoint::ceil(x); #else #if __GNUC__ && __i386__ // ceil() and (int)() are implemented separately, which results // in changing the FPCW multiple times - so we optimize it with // some inline assembly Gushort oldCW, newCW, t; int result; __asm__ volatile("fldl %4\n" "fnstcw %0\n" "movw %0, %3\n" "andw $0xf3ff, %3\n" "orw $0x0800, %3\n" "movw %3, %1\n" // round up "fldcw %1\n" "fistpl %2\n" "fldcw %0\n" : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) : "m" (x)); return result; #elif defined(WIN32) && defined(_M_IX86) // ceil() and (int)() are implemented separately, which results // in changing the FPCW multiple times - so we optimize it with // some inline assembly Gushort oldCW, newCW; int result; __asm fld QWORD PTR x __asm fnstcw WORD PTR oldCW __asm mov ax, WORD PTR oldCW __asm and ax, 0xf3ff __asm or ax, 0x0800 __asm mov WORD PTR newCW, ax // round up __asm fldcw WORD PTR newCW __asm fistp DWORD PTR result __asm fldcw WORD PTR oldCW return result; #else return (int)ceil(x); #endif #endif } static inline int splashRound(SplashCoord x) { #if USE_FIXEDPOINT return FixedPoint::round(x); #else #if __GNUC__ && __i386__ // this could use round-to-nearest mode and avoid the "+0.5", // but that produces slightly different results (because i+0.5 // sometimes rounds up and sometimes down using the even rule) Gushort oldCW, newCW, t; int result; x += 0.5; __asm__ volatile("fldl %4\n" "fnstcw %0\n" "movw %0, %3\n" "andw $0xf3ff, %3\n" "orw $0x0400, %3\n" "movw %3, %1\n" // round down "fldcw %1\n" "fistpl %2\n" "fldcw %0\n" : "=m" (oldCW), "=m" (newCW), "=m" (result), "=r" (t) : "m" (x)); return result; #elif defined(WIN32) && defined(_M_IX86) // this could use round-to-nearest mode and avoid the "+0.5", // but that produces slightly different results (because i+0.5 // sometimes rounds up and sometimes down using the even rule) Gushort oldCW, newCW; int result; x += 0.5; __asm fld QWORD PTR x __asm fnstcw WORD PTR oldCW __asm mov ax, WORD PTR oldCW __asm and ax, 0xf3ff __asm or ax, 0x0400 __asm mov WORD PTR newCW, ax // round down __asm fldcw WORD PTR newCW __asm fistp DWORD PTR result __asm fldcw WORD PTR oldCW return result; #else return (int)floor(x + 0.5); #endif #endif } static inline SplashCoord splashAvg(SplashCoord x, SplashCoord y) { #if USE_FIXEDPOINT return FixedPoint::avg(x, y); #else return 0.5 * (x + y); #endif } static inline SplashCoord splashSqrt(SplashCoord x) { #if USE_FIXEDPOINT return FixedPoint::sqrt(x); #else return sqrt(x); #endif } static inline SplashCoord splashPow(SplashCoord x, SplashCoord y) { #if USE_FIXEDPOINT return FixedPoint::pow(x, y); #else return pow(x, y); #endif } static inline SplashCoord splashDist(SplashCoord x0, SplashCoord y0, SplashCoord x1, SplashCoord y1) { SplashCoord dx, dy; dx = x1 - x0; dy = y1 - y0; #if USE_FIXEDPOINT // this handles the situation where dx*dx or dy*dy is too large to // fit in the 16.16 fixed point format SplashCoord dxa, dya, d; dxa = splashAbs(dx); dya = splashAbs(dy); if (dxa == 0 && dya == 0) { return 0; } else if (dxa > dya) { d = dya / dxa; return dxa * FixedPoint::sqrt(d*d + 1); } else { d = dxa / dya; return dya * FixedPoint::sqrt(d*d + 1); } #else return sqrt(dx * dx + dy * dy); #endif } static inline GBool splashCheckDet(SplashCoord m11, SplashCoord m12, SplashCoord m21, SplashCoord m22, SplashCoord epsilon) { #if USE_FIXEDPOINT return FixedPoint::checkDet(m11, m12, m21, m22, epsilon); #else return fabs(m11 * m22 - m12 * m21) >= epsilon; #endif } #endif xpdf-3.03/splash/SplashPath.h0000644000076400007640000000675411622305345015441 0ustar dereknderekn//======================================================================== // // SplashPath.h // //======================================================================== #ifndef SPLASHPATH_H #define SPLASHPATH_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashTypes.h" //------------------------------------------------------------------------ // SplashPathPoint //------------------------------------------------------------------------ struct SplashPathPoint { SplashCoord x, y; }; //------------------------------------------------------------------------ // SplashPath.flags //------------------------------------------------------------------------ // first point on each subpath sets this flag #define splashPathFirst 0x01 // last point on each subpath sets this flag #define splashPathLast 0x02 // if the subpath is closed, its first and last points must be // identical, and must set this flag #define splashPathClosed 0x04 // curve control points set this flag #define splashPathCurve 0x08 //------------------------------------------------------------------------ // SplashPathHint //------------------------------------------------------------------------ struct SplashPathHint { int ctrl0, ctrl1; int firstPt, lastPt; }; //------------------------------------------------------------------------ // SplashPath //------------------------------------------------------------------------ class SplashPath { public: // Create an empty path. SplashPath(); // Copy a path. SplashPath *copy() { return new SplashPath(this); } ~SplashPath(); // Append to . void append(SplashPath *path); // Start a new subpath. SplashError moveTo(SplashCoord x, SplashCoord y); // Add a line segment to the last subpath. SplashError lineTo(SplashCoord x, SplashCoord y); // Add a third-order (cubic) Bezier curve segment to the last // subpath. SplashError curveTo(SplashCoord x1, SplashCoord y1, SplashCoord x2, SplashCoord y2, SplashCoord x3, SplashCoord y3); // Close the last subpath, adding a line segment if necessary. If // is true, this adds a line segment even if the current // point is equal to the first point in the subpath. SplashError close(GBool force = gFalse); // Add a stroke adjustment hint. The controlling segments are // and (where segments are identified by their first // point), and the points to be adjusted are .. . void addStrokeAdjustHint(int ctrl0, int ctrl1, int firstPt, int lastPt); // Add (, ) to every point on this path. void offset(SplashCoord dx, SplashCoord dy); // Get the points on the path. int getLength() { return length; } void getPoint(int i, double *x, double *y, Guchar *f) { *x = pts[i].x; *y = pts[i].y; *f = flags[i]; } // Get the current point. GBool getCurPt(SplashCoord *x, SplashCoord *y); private: SplashPath(SplashPath *path); void grow(int nPts); GBool noCurrentPoint() { return curSubpath == length; } GBool onePointSubpath() { return curSubpath == length - 1; } GBool openSubpath() { return curSubpath < length - 1; } SplashPathPoint *pts; // array of points Guchar *flags; // array of flags int length, size; // length/size of the pts and flags arrays int curSubpath; // index of first point in last subpath SplashPathHint *hints; // list of hints int hintsLength, hintsSize; friend class SplashXPath; friend class Splash; }; #endif xpdf-3.03/splash/SplashT1Font.cc0000644000076400007640000001777711622305345016025 0ustar dereknderekn//======================================================================== // // SplashT1Font.cc // //======================================================================== #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" #include "SplashPath.h" #include "SplashT1FontEngine.h" #include "SplashT1FontFile.h" #include "SplashT1Font.h" //------------------------------------------------------------------------ static Guchar bitReverse[256] = { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff }; //------------------------------------------------------------------------ // SplashT1Font //------------------------------------------------------------------------ SplashT1Font::SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA): SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) { T1_TMATRIX matrix; BBox bbox; SplashCoord bbx0, bby0, bbx1, bby1; int x, y; t1libID = T1_CopyFont(fontFileA->t1libID); outlineID = -1; // compute font size size = (float)splashDist(0, 0, mat[2], mat[3]); // transform the four corners of the font bounding box -- the min // and max values form the bounding box of the transformed font bbox = T1_GetFontBBox(t1libID); bbx0 = 0.001 * bbox.llx; bby0 = 0.001 * bbox.lly; bbx1 = 0.001 * bbox.urx; bby1 = 0.001 * bbox.ury; // some fonts are completely broken, so we fake it (with values // large enough that most glyphs should fit) if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { bbx0 = bby0 = -0.5; bbx1 = bby1 = 1.5; } x = (int)(mat[0] * bbx0 + mat[2] * bby0); xMin = xMax = x; y = (int)(mat[1] * bbx0 + mat[3] * bby0); yMin = yMax = y; x = (int)(mat[0] * bbx0 + mat[2] * bby1); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * bbx0 + mat[3] * bby1); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)(mat[0] * bbx1 + mat[2] * bby0); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * bbx1 + mat[3] * bby0); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)(mat[0] * bbx1 + mat[2] * bby1); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * bbx1 + mat[3] * bby1); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } // This is a kludge: some buggy PDF generators embed fonts with // zero bounding boxes. if (xMax == xMin) { xMin = 0; xMax = (int)size; } if (yMax == yMin) { yMin = 0; yMax = (int)(1.2 * size); } // Another kludge: an unusually large xMin or yMin coordinate is // probably wrong. if (xMin > 0) { xMin = 0; } if (yMin > 0) { yMin = 0; } // Another kludge: t1lib doesn't correctly handle fonts with // real (non-integer) bounding box coordinates. if (xMax - xMin > 5000) { xMin = 0; xMax = (int)size; } if (yMax - yMin > 5000) { yMin = 0; yMax = (int)(1.2 * size); } // transform the font matrix.cxx = (double)mat[0] / size; matrix.cxy = (double)mat[1] / size; matrix.cyx = (double)mat[2] / size; matrix.cyy = (double)mat[3] / size; T1_TransformFont(t1libID, &matrix); } SplashT1Font::~SplashT1Font() { T1_DeleteFont(t1libID); if (outlineID >= 0) { T1_DeleteFont(outlineID); } } GBool SplashT1Font::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { return SplashFont::getGlyph(c, 0, 0, bitmap); } GBool SplashT1Font::makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { GLYPH *glyph; int n, i; if (aa) { glyph = T1_AASetChar(t1libID, c, size, NULL); } else { glyph = T1_SetChar(t1libID, c, size, NULL); } if (!glyph) { return gFalse; } bitmap->x = -glyph->metrics.leftSideBearing; bitmap->y = glyph->metrics.ascent; bitmap->w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; bitmap->h = glyph->metrics.ascent - glyph->metrics.descent; bitmap->aa = aa; if (aa) { bitmap->data = (Guchar *)glyph->bits; bitmap->freeData = gFalse; } else { n = bitmap->h * ((bitmap->w + 7) >> 3); bitmap->data = (Guchar *)gmalloc(n); for (i = 0; i < n; ++i) { bitmap->data[i] = bitReverse[glyph->bits[i] & 0xff]; } bitmap->freeData = gTrue; } return gTrue; } SplashPath *SplashT1Font::getGlyphPath(int c) { T1_TMATRIX matrix; SplashPath *path; T1_OUTLINE *outline; T1_PATHSEGMENT *seg; T1_BEZIERSEGMENT *bez; int x, y, x1, y1; GBool needClose; if (outlineID < 0) { outlineID = T1_CopyFont(((SplashT1FontFile *)fontFile)->t1libID); outlineSize = (float)splashDist(0, 0, textMat[2], textMat[3]); matrix.cxx = (double)textMat[0] / outlineSize; matrix.cxy = (double)textMat[1] / outlineSize; matrix.cyx = (double)textMat[2] / outlineSize; matrix.cyy = (double)textMat[3] / outlineSize; // t1lib doesn't seem to handle small sizes correctly here, so set // the size to 1000, and scale the resulting coordinates later outlineMul = (float)(outlineSize / 65536000.0); outlineSize = 1000; T1_TransformFont(outlineID, &matrix); } path = new SplashPath(); if ((outline = T1_GetCharOutline(outlineID, c, outlineSize, NULL))) { // NB: t1lib uses integer coordinates here; we keep a running // (x,y) total as integers, so that the final point in the path is // exactly the same as the first point, thus avoiding weird // mitered join glitches x = y = 0; needClose = gFalse; for (seg = outline; seg; seg = seg->link) { switch (seg->type) { case T1_PATHTYPE_MOVE: if (needClose) { path->close(); needClose = gFalse; } x += seg->dest.x; y += seg->dest.y; path->moveTo(outlineMul * x, -outlineMul * y); break; case T1_PATHTYPE_LINE: x += seg->dest.x; y += seg->dest.y; path->lineTo(outlineMul * x, -outlineMul * y); needClose = gTrue; break; case T1_PATHTYPE_BEZIER: bez = (T1_BEZIERSEGMENT *)seg; x1 = x + bez->dest.x; y1 = y + bez->dest.y; path->curveTo(outlineMul * (x + bez->B.x), -outlineMul * (y + bez->B.y), outlineMul * (x + bez->C.x), -outlineMul * (y + bez->C.y), outlineMul * x1, -outlineMul * y1); x = x1; y = y1; needClose = gTrue; break; } } if (needClose) { path->close(); } T1_FreeOutline(outline); } return path; } #endif // HAVE_T1LIB_H xpdf-3.03/splash/SplashTypes.h0000644000076400007640000000735711622305345015651 0ustar dereknderekn//======================================================================== // // SplashTypes.h // //======================================================================== #ifndef SPLASHTYPES_H #define SPLASHTYPES_H #include #include "gtypes.h" //------------------------------------------------------------------------ // coordinates //------------------------------------------------------------------------ #if USE_FIXEDPOINT #include "FixedPoint.h" typedef FixedPoint SplashCoord; #else typedef double SplashCoord; #endif //------------------------------------------------------------------------ // antialiasing //------------------------------------------------------------------------ #define splashAASize 4 //------------------------------------------------------------------------ // colors //------------------------------------------------------------------------ enum SplashColorMode { splashModeMono1, // 1 bit per component, 8 pixels per byte, // MSbit is on the left splashModeMono8, // 1 byte per component, 1 byte per pixel splashModeRGB8, // 1 byte per component, 3 bytes per pixel: // RGBRGB... splashModeBGR8 // 1 byte per component, 3 bytes per pixel: // BGRBGR... #if SPLASH_CMYK , splashModeCMYK8 // 1 byte per component, 4 bytes per pixel: // CMYKCMYK... #endif }; // number of components in each color mode // (defined in SplashState.cc) extern int splashColorModeNComps[]; // max number of components in any SplashColor #define splashMaxColorComps 3 #if SPLASH_CMYK # undef splashMaxColorComps # define splashMaxColorComps 4 #endif typedef Guchar SplashColor[splashMaxColorComps]; typedef Guchar *SplashColorPtr; // RGB8 static inline Guchar splashRGB8R(SplashColorPtr rgb8) { return rgb8[0]; } static inline Guchar splashRGB8G(SplashColorPtr rgb8) { return rgb8[1]; } static inline Guchar splashRGB8B(SplashColorPtr rgb8) { return rgb8[2]; } // BGR8 static inline Guchar splashBGR8R(SplashColorPtr bgr8) { return bgr8[2]; } static inline Guchar splashBGR8G(SplashColorPtr bgr8) { return bgr8[1]; } static inline Guchar splashBGR8B(SplashColorPtr bgr8) { return bgr8[0]; } #if SPLASH_CMYK // CMYK8 static inline Guchar splashCMYK8C(SplashColorPtr cmyk8) { return cmyk8[0]; } static inline Guchar splashCMYK8M(SplashColorPtr cmyk8) { return cmyk8[1]; } static inline Guchar splashCMYK8Y(SplashColorPtr cmyk8) { return cmyk8[2]; } static inline Guchar splashCMYK8K(SplashColorPtr cmyk8) { return cmyk8[3]; } #endif static inline void splashColorCopy(SplashColorPtr dest, SplashColorPtr src) { dest[0] = src[0]; dest[1] = src[1]; dest[2] = src[2]; #if SPLASH_CMYK dest[3] = src[3]; #endif } static inline void splashColorXor(SplashColorPtr dest, SplashColorPtr src) { dest[0] ^= src[0]; dest[1] ^= src[1]; dest[2] ^= src[2]; #if SPLASH_CMYK dest[3] ^= src[3]; #endif } //------------------------------------------------------------------------ // blend functions //------------------------------------------------------------------------ typedef void (*SplashBlendFunc)(SplashColorPtr src, SplashColorPtr dest, SplashColorPtr blend, SplashColorMode cm); //------------------------------------------------------------------------ // screen parameters //------------------------------------------------------------------------ enum SplashScreenType { splashScreenDispersed, splashScreenClustered, splashScreenStochasticClustered }; struct SplashScreenParams { SplashScreenType type; int size; int dotRadius; SplashCoord gamma; SplashCoord blackThreshold; SplashCoord whiteThreshold; }; //------------------------------------------------------------------------ // error results //------------------------------------------------------------------------ typedef int SplashError; #endif xpdf-3.03/splash/SplashFTFont.cc0000644000076400007640000003044111622305345016031 0ustar dereknderekn//======================================================================== // // SplashFTFont.cc // //======================================================================== #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include FT_OUTLINE_H #include FT_SIZES_H #include FT_GLYPH_H #include "gmem.h" #include "SplashMath.h" #include "SplashGlyphBitmap.h" #include "SplashPath.h" #include "SplashFontEngine.h" #include "SplashFTFontEngine.h" #include "SplashFTFontFile.h" #include "SplashFTFont.h" //------------------------------------------------------------------------ static int glyphPathMoveTo(const FT_Vector *pt, void *path); static int glyphPathLineTo(const FT_Vector *pt, void *path); static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path); static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path); //------------------------------------------------------------------------ // SplashFTFont //------------------------------------------------------------------------ SplashFTFont::SplashFTFont(SplashFTFontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA): SplashFont(fontFileA, matA, textMatA, fontFileA->engine->aa) { FT_Face face; int size, div; int x, y; #if USE_FIXEDPOINT SplashCoord scale; #endif face = fontFileA->face; if (FT_New_Size(face, &sizeObj)) { return; } face->size = sizeObj; size = splashRound(splashDist(0, 0, mat[2], mat[3])); if (size < 1) { size = 1; } if (FT_Set_Pixel_Sizes(face, 0, size)) { return; } // if the textMat values are too small, FreeType's fixed point // arithmetic doesn't work so well textScale = splashDist(0, 0, textMat[2], textMat[3]) / size; div = face->bbox.xMax > 20000 ? 65536 : 1; #if USE_FIXEDPOINT scale = (SplashCoord)1 / (SplashCoord)face->units_per_EM; // transform the four corners of the font bounding box -- the min // and max values form the bounding box of the transformed font x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + mat[2] * (scale * (face->bbox.yMin / div))); xMin = xMax = x; y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + mat[3] * (scale * (face->bbox.yMin / div))); yMin = yMax = y; x = (int)(mat[0] * (scale * (face->bbox.xMin / div)) + mat[2] * (scale * (face->bbox.yMax / div))); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * (scale * (face->bbox.xMin / div)) + mat[3] * (scale * (face->bbox.yMax / div))); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + mat[2] * (scale * (face->bbox.yMin / div))); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + mat[3] * (scale * (face->bbox.yMin / div))); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)(mat[0] * (scale * (face->bbox.xMax / div)) + mat[2] * (scale * (face->bbox.yMax / div))); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)(mat[1] * (scale * (face->bbox.xMax / div)) + mat[3] * (scale * (face->bbox.yMax / div))); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } #else // USE_FIXEDPOINT // transform the four corners of the font bounding box -- the min // and max values form the bounding box of the transformed font x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMin) / (div * face->units_per_EM)); xMin = xMax = x; y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMin) / (div * face->units_per_EM)); yMin = yMax = y; x = (int)((mat[0] * face->bbox.xMin + mat[2] * face->bbox.yMax) / (div * face->units_per_EM)); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)((mat[1] * face->bbox.xMin + mat[3] * face->bbox.yMax) / (div * face->units_per_EM)); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMin) / (div * face->units_per_EM)); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMin) / (div * face->units_per_EM)); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } x = (int)((mat[0] * face->bbox.xMax + mat[2] * face->bbox.yMax) / (div * face->units_per_EM)); if (x < xMin) { xMin = x; } else if (x > xMax) { xMax = x; } y = (int)((mat[1] * face->bbox.xMax + mat[3] * face->bbox.yMax) / (div * face->units_per_EM)); if (y < yMin) { yMin = y; } else if (y > yMax) { yMax = y; } #endif // USE_FIXEDPOINT // This is a kludge: some buggy PDF generators embed fonts with // zero bounding boxes. if (xMax == xMin) { xMin = 0; xMax = size; } if (yMax == yMin) { yMin = 0; yMax = (int)((SplashCoord)1.2 * size); } // compute the transform matrix #if USE_FIXEDPOINT matrix.xx = (FT_Fixed)((mat[0] / size).get16Dot16()); matrix.yx = (FT_Fixed)((mat[1] / size).get16Dot16()); matrix.xy = (FT_Fixed)((mat[2] / size).get16Dot16()); matrix.yy = (FT_Fixed)((mat[3] / size).get16Dot16()); textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)).get16Dot16()); textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)).get16Dot16()); textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)).get16Dot16()); textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)).get16Dot16()); #else matrix.xx = (FT_Fixed)((mat[0] / size) * 65536); matrix.yx = (FT_Fixed)((mat[1] / size) * 65536); matrix.xy = (FT_Fixed)((mat[2] / size) * 65536); matrix.yy = (FT_Fixed)((mat[3] / size) * 65536); textMatrix.xx = (FT_Fixed)((textMat[0] / (textScale * size)) * 65536); textMatrix.yx = (FT_Fixed)((textMat[1] / (textScale * size)) * 65536); textMatrix.xy = (FT_Fixed)((textMat[2] / (textScale * size)) * 65536); textMatrix.yy = (FT_Fixed)((textMat[3] / (textScale * size)) * 65536); #endif } SplashFTFont::~SplashFTFont() { } GBool SplashFTFont::getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { return SplashFont::getGlyph(c, xFrac, 0, bitmap); } GBool SplashFTFont::makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap) { SplashFTFontFile *ff; FT_Vector offset; FT_GlyphSlot slot; FT_UInt gid; FT_Int32 flags; int rowSize; Guchar *p, *q; int i; ff = (SplashFTFontFile *)fontFile; ff->face->size = sizeObj; offset.x = (FT_Pos)(int)((SplashCoord)xFrac * splashFontFractionMul * 64); offset.y = 0; FT_Set_Transform(ff->face, &matrix, &offset); slot = ff->face->glyph; if (ff->codeToGID && c < ff->codeToGIDLen) { gid = (FT_UInt)ff->codeToGID[c]; } else { gid = (FT_UInt)c; } if (ff->trueType && gid < 0) { // skip the TrueType notdef glyph return gFalse; } flags = 0; if (aa) { flags |= FT_LOAD_NO_BITMAP; } if (ff->engine->flags & splashFTNoHinting) { flags |= FT_LOAD_NO_HINTING; } else if (ff->trueType) { // FT2's autohinting doesn't always work very well (especially with // font subsets), so turn it off if anti-aliasing is enabled; if // anti-aliasing is disabled, this seems to be a tossup - some fonts // look better with hinting, some without, so leave hinting on if (aa) { flags |= FT_LOAD_NO_AUTOHINT; } } else if (ff->type1) { // Type 1 fonts seem to look better with 'light' hinting mode flags |= FT_LOAD_TARGET_LIGHT; } if (FT_Load_Glyph(ff->face, gid, flags)) { return gFalse; } if (FT_Render_Glyph(slot, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO)) { return gFalse; } if (slot->bitmap.width == 0 || slot->bitmap.rows == 0) { // this can happen if (a) the glyph is really tiny or (b) the // metrics in the TrueType file are broken return gFalse; } bitmap->x = -slot->bitmap_left; bitmap->y = slot->bitmap_top; bitmap->w = slot->bitmap.width; bitmap->h = slot->bitmap.rows; bitmap->aa = aa; if (aa) { rowSize = bitmap->w; } else { rowSize = (bitmap->w + 7) >> 3; } bitmap->data = (Guchar *)gmallocn(bitmap->h, rowSize); bitmap->freeData = gTrue; for (i = 0, p = bitmap->data, q = slot->bitmap.buffer; i < bitmap->h; ++i, p += rowSize, q += slot->bitmap.pitch) { memcpy(p, q, rowSize); } return gTrue; } struct SplashFTFontPath { SplashPath *path; SplashCoord textScale; GBool needClose; }; SplashPath *SplashFTFont::getGlyphPath(int c) { static FT_Outline_Funcs outlineFuncs = { #if FREETYPE_MINOR <= 1 (int (*)(FT_Vector *, void *))&glyphPathMoveTo, (int (*)(FT_Vector *, void *))&glyphPathLineTo, (int (*)(FT_Vector *, FT_Vector *, void *))&glyphPathConicTo, (int (*)(FT_Vector *, FT_Vector *, FT_Vector *, void *))&glyphPathCubicTo, #else &glyphPathMoveTo, &glyphPathLineTo, &glyphPathConicTo, &glyphPathCubicTo, #endif 0, 0 }; SplashFTFontFile *ff; SplashFTFontPath path; FT_GlyphSlot slot; FT_UInt gid; FT_Glyph glyph; ff = (SplashFTFontFile *)fontFile; ff->face->size = sizeObj; FT_Set_Transform(ff->face, &textMatrix, NULL); slot = ff->face->glyph; if (ff->codeToGID && c < ff->codeToGIDLen) { gid = ff->codeToGID[c]; } else { gid = (FT_UInt)c; } if (ff->trueType && gid < 0) { // skip the TrueType notdef glyph return NULL; } if (FT_Load_Glyph(ff->face, gid, FT_LOAD_NO_BITMAP)) { return NULL; } if (FT_Get_Glyph(slot, &glyph)) { return NULL; } path.path = new SplashPath(); path.textScale = textScale; path.needClose = gFalse; FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, &outlineFuncs, &path); if (path.needClose) { path.path->close(); } FT_Done_Glyph(glyph); return path.path; } static int glyphPathMoveTo(const FT_Vector *pt, void *path) { SplashFTFontPath *p = (SplashFTFontPath *)path; if (p->needClose) { p->path->close(); p->needClose = gFalse; } p->path->moveTo((SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0); return 0; } static int glyphPathLineTo(const FT_Vector *pt, void *path) { SplashFTFontPath *p = (SplashFTFontPath *)path; p->path->lineTo((SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0); p->needClose = gTrue; return 0; } static int glyphPathConicTo(const FT_Vector *ctrl, const FT_Vector *pt, void *path) { SplashFTFontPath *p = (SplashFTFontPath *)path; SplashCoord x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; if (!p->path->getCurPt(&x0, &y0)) { return 0; } xc = (SplashCoord)ctrl->x * p->textScale / 64.0; yc = (SplashCoord)ctrl->y * p->textScale / 64.0; x3 = (SplashCoord)pt->x * p->textScale / 64.0; y3 = (SplashCoord)pt->y * p->textScale / 64.0; // A second-order Bezier curve is defined by two endpoints, p0 and // p3, and one control point, pc: // // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 // // A third-order Bezier curve is defined by the same two endpoints, // p0 and p3, and two control points, p1 and p2: // // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 // // Applying some algebra, we can convert a second-order curve to a // third-order curve: // // p1 = (1/3) * (p0 + 2pc) // p2 = (1/3) * (2pc + p3) x1 = (SplashCoord)(1.0 / 3.0) * (x0 + (SplashCoord)2 * xc); y1 = (SplashCoord)(1.0 / 3.0) * (y0 + (SplashCoord)2 * yc); x2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * xc + x3); y2 = (SplashCoord)(1.0 / 3.0) * ((SplashCoord)2 * yc + y3); p->path->curveTo(x1, y1, x2, y2, x3, y3); p->needClose = gTrue; return 0; } static int glyphPathCubicTo(const FT_Vector *ctrl1, const FT_Vector *ctrl2, const FT_Vector *pt, void *path) { SplashFTFontPath *p = (SplashFTFontPath *)path; p->path->curveTo((SplashCoord)ctrl1->x * p->textScale / 64.0, (SplashCoord)ctrl1->y * p->textScale / 64.0, (SplashCoord)ctrl2->x * p->textScale / 64.0, (SplashCoord)ctrl2->y * p->textScale / 64.0, (SplashCoord)pt->x * p->textScale / 64.0, (SplashCoord)pt->y * p->textScale / 64.0); p->needClose = gTrue; return 0; } #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H xpdf-3.03/splash/Makefile.in0000644000076400007640000000440311622305345015253 0ustar dereknderekn#======================================================================== # # Splash library Makefile # # Copyright 2003 Glyph & Cog, LLC # #======================================================================== SHELL = /bin/sh srcdir = @srcdir@ VPATH = @srcdir@ GOOSRCDIR = $(srcdir)/../goo GOOLIBDIR = ../goo FOFISRCDIR = $(srcdir)/../fofi FOFILIBDIR = ../fofi CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(FOFISRCDIR) -I$(srcdir) @t1_CFLAGS@ @freetype2_CFLAGS@ CXX = @CXX@ AR = @AR@ RANLIB = @RANLIB@ LIBPREFIX = @LIBPREFIX@ #------------------------------------------------------------------------ .SUFFIXES: .cc .cc.o: $(CXX) $(CXXFLAGS) -c $< #------------------------------------------------------------------------ CXX_SRC = \ $(srcdir)/Splash.cc \ $(srcdir)/SplashBitmap.cc \ $(srcdir)/SplashClip.cc \ $(srcdir)/SplashFTFont.cc \ $(srcdir)/SplashFTFontEngine.cc \ $(srcdir)/SplashFTFontFile.cc \ $(srcdir)/SplashFont.cc \ $(srcdir)/SplashFontEngine.cc \ $(srcdir)/SplashFontFile.cc \ $(srcdir)/SplashFontFileID.cc \ $(srcdir)/SplashPath.cc \ $(srcdir)/SplashPattern.cc \ $(srcdir)/SplashScreen.cc \ $(srcdir)/SplashState.cc \ $(srcdir)/SplashT1Font.cc \ $(srcdir)/SplashT1FontEngine.cc \ $(srcdir)/SplashT1FontFile.cc \ $(srcdir)/SplashXPath.cc \ $(srcdir)/SplashXPathScanner.cc #------------------------------------------------------------------------ all: $(LIBPREFIX)splash.a #------------------------------------------------------------------------ SPLASH_OBJS = \ Splash.o \ SplashBitmap.o \ SplashClip.o \ SplashFTFont.o \ SplashFTFontEngine.o \ SplashFTFontFile.o \ SplashFont.o \ SplashFontEngine.o \ SplashFontFile.o \ SplashFontFileID.o \ SplashPath.o \ SplashPattern.o \ SplashScreen.o \ SplashState.o \ SplashT1Font.o \ SplashT1FontEngine.o \ SplashT1FontFile.o \ SplashXPath.o \ SplashXPathScanner.o $(LIBPREFIX)splash.a: $(SPLASH_OBJS) rm -f $(LIBPREFIX)splash.a $(AR) $(LIBPREFIX)splash.a $(SPLASH_OBJS) $(RANLIB) $(LIBPREFIX)splash.a #------------------------------------------------------------------------ clean: rm -f $(SPLASH_OBJS) $(LIBPREFIX)splash.a #------------------------------------------------------------------------ depend: $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep include Makefile.dep xpdf-3.03/splash/SplashFontEngine.h0000644000076400007640000000535411622305345016574 0ustar dereknderekn//======================================================================== // // SplashFontEngine.h // //======================================================================== #ifndef SPLASHFONTENGINE_H #define SPLASHFONTENGINE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" class SplashT1FontEngine; class SplashFTFontEngine; class SplashDTFontEngine; class SplashDT4FontEngine; class SplashFontFile; class SplashFontFileID; class SplashFont; //------------------------------------------------------------------------ #define splashFontCacheSize 16 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #define splashFTNoHinting (1 << 0) #endif //------------------------------------------------------------------------ // SplashFontEngine //------------------------------------------------------------------------ class SplashFontEngine { public: // Create a font engine. SplashFontEngine( #if HAVE_T1LIB_H GBool enableT1lib, #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H GBool enableFreeType, Guint freeTypeFlags, #endif GBool aa); ~SplashFontEngine(); // Get a font file from the cache. Returns NULL if there is no // matching entry in the cache. SplashFontFile *getFontFile(SplashFontFileID *id); // Load fonts - these create new SplashFontFile objects. SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, GBool deleteFile); SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, int *codeToGID, int codeToGIDLen); SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, int fontNum, GBool deleteFile, int *codeToGID, int codeToGIDLen, char *fontName); // Get a font - this does a cache lookup first, and if not found, // creates a new SplashFont object and adds it to the cache. The // matrix, mat = textMat * ctm: // [ mat[0] mat[1] ] // [ mat[2] mat[3] ] // specifies the font transform in PostScript style: // [x' y'] = [x y] * mat // Note that the Splash y axis points downward. SplashFont *getFont(SplashFontFile *fontFile, SplashCoord *textMat, SplashCoord *ctm); private: SplashFont *fontCache[splashFontCacheSize]; #if HAVE_T1LIB_H SplashT1FontEngine *t1Engine; #endif #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H SplashFTFontEngine *ftEngine; #endif }; #endif xpdf-3.03/splash/SplashT1FontFile.cc0000644000076400007640000000436111622305345016606 0ustar dereknderekn//======================================================================== // // SplashT1FontFile.cc // //======================================================================== #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "SplashT1FontEngine.h" #include "SplashT1Font.h" #include "SplashT1FontFile.h" //------------------------------------------------------------------------ // SplashT1FontFile //------------------------------------------------------------------------ SplashFontFile *SplashT1FontFile::loadType1Font(SplashT1FontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, const char **encA) { int t1libIDA; const char **encTmp; char *encStrTmp; int encStrSize; char *encPtr; int i; // load the font file if ((t1libIDA = T1_AddFont(fileNameA)) < 0) { return NULL; } T1_LoadFont(t1libIDA); // reencode it encStrSize = 0; for (i = 0; i < 256; ++i) { if (encA[i]) { encStrSize += strlen(encA[i]) + 1; } } encTmp = (const char **)gmallocn(257, sizeof(char *)); encStrTmp = (char *)gmallocn(encStrSize, sizeof(char)); encPtr = encStrTmp; for (i = 0; i < 256; ++i) { if (encA[i]) { strcpy(encPtr, encA[i]); encTmp[i] = encPtr; encPtr += strlen(encPtr) + 1; } else { encTmp[i] = ".notdef"; } } encTmp[256] = "custom"; T1_ReencodeFont(t1libIDA, (char **)encTmp); return new SplashT1FontFile(engineA, idA, fileNameA, deleteFileA, t1libIDA, encTmp, encStrTmp); } SplashT1FontFile::SplashT1FontFile(SplashT1FontEngine *engineA, SplashFontFileID *idA, char *fileNameA, GBool deleteFileA, int t1libIDA, const char **encA, char *encStrA): SplashFontFile(idA, fileNameA, deleteFileA) { engine = engineA; t1libID = t1libIDA; enc = encA; encStr = encStrA; } SplashT1FontFile::~SplashT1FontFile() { gfree(encStr); gfree(enc); T1_DeleteFont(t1libID); } SplashFont *SplashT1FontFile::makeFont(SplashCoord *mat, SplashCoord *textMat) { SplashFont *font; font = new SplashT1Font(this, mat, textMat); font->initCache(); return font; } #endif // HAVE_T1LIB_H xpdf-3.03/splash/SplashFTFontEngine.h0000644000076400007640000000341211622305345017017 0ustar dereknderekn//======================================================================== // // SplashFTFontEngine.h // //======================================================================== #ifndef SPLASHFTFONTENGINE_H #define SPLASHFTFONTENGINE_H #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include FT_FREETYPE_H #include "gtypes.h" class SplashFontFile; class SplashFontFileID; //------------------------------------------------------------------------ // SplashFTFontEngine //------------------------------------------------------------------------ class SplashFTFontEngine { public: static SplashFTFontEngine *init(GBool aaA, Guint flagsA); ~SplashFTFontEngine(); // Load fonts. SplashFontFile *loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc); SplashFontFile *loadCIDFont(SplashFontFileID *idA, char *fileName, GBool deleteFile); SplashFontFile *loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, int *codeToGID, int codeToGIDLen); SplashFontFile *loadTrueTypeFont(SplashFontFileID *idA, char *fileName, int fontNum, GBool deleteFile, int *codeToGID, int codeToGIDLen); private: SplashFTFontEngine(GBool aaA, Guint flagsA, FT_Library libA); GBool aa; Guint flags; FT_Library lib; GBool useCIDs; friend class SplashFTFontFile; friend class SplashFTFont; }; #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #endif xpdf-3.03/splash/SplashFontFile.cc0000644000076400007640000000212511622305345016375 0ustar dereknderekn//======================================================================== // // SplashFontFile.cc // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #ifndef WIN32 # include #endif #include "GString.h" #include "SplashFontFile.h" #include "SplashFontFileID.h" #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #endif //------------------------------------------------------------------------ // SplashFontFile //------------------------------------------------------------------------ SplashFontFile::SplashFontFile(SplashFontFileID *idA, char *fileNameA, GBool deleteFileA) { id = idA; fileName = new GString(fileNameA); deleteFile = deleteFileA; refCnt = 0; } SplashFontFile::~SplashFontFile() { if (deleteFile) { unlink(fileName->getCString()); } delete fileName; delete id; } void SplashFontFile::incRefCnt() { ++refCnt; } void SplashFontFile::decRefCnt() { if (!--refCnt) { delete this; } } xpdf-3.03/splash/SplashFTFontEngine.cc0000644000076400007640000001105411622305345017156 0ustar dereknderekn//======================================================================== // // SplashFTFontEngine.cc // //======================================================================== #include #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #ifndef WIN32 # include #endif #include "gmem.h" #include "GString.h" #include "gfile.h" #include "FoFiTrueType.h" #include "FoFiType1C.h" #include "SplashFTFontFile.h" #include "SplashFTFontEngine.h" #ifdef VMS #if (__VMS_VER < 70000000) extern "C" int unlink(char *filename); #endif #endif //------------------------------------------------------------------------ static void fileWrite(void *stream, const char *data, int len) { fwrite(data, 1, len, (FILE *)stream); } //------------------------------------------------------------------------ // SplashFTFontEngine //------------------------------------------------------------------------ SplashFTFontEngine::SplashFTFontEngine(GBool aaA, Guint flagsA, FT_Library libA) { FT_Int major, minor, patch; aa = aaA; flags = flagsA; lib = libA; // as of FT 2.1.8, CID fonts are indexed by CID instead of GID FT_Library_Version(lib, &major, &minor, &patch); useCIDs = major > 2 || (major == 2 && (minor > 1 || (minor == 1 && patch > 7))); } SplashFTFontEngine *SplashFTFontEngine::init(GBool aaA, Guint flagsA) { FT_Library libA; if (FT_Init_FreeType(&libA)) { return NULL; } return new SplashFTFontEngine(aaA, flagsA, libA); } SplashFTFontEngine::~SplashFTFontEngine() { FT_Done_FreeType(lib); } SplashFontFile *SplashFTFontEngine::loadType1Font(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); } SplashFontFile *SplashFTFontEngine::loadType1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); } SplashFontFile *SplashFTFontEngine::loadOpenTypeT1CFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, const char **enc) { return SplashFTFontFile::loadType1Font(this, idA, fileName, deleteFile, enc); } SplashFontFile *SplashFTFontEngine::loadCIDFont(SplashFontFileID *idA, char *fileName, GBool deleteFile) { FoFiType1C *ff; int *cidToGIDMap; int nCIDs; SplashFontFile *ret; // check for a CFF font if (useCIDs) { cidToGIDMap = NULL; nCIDs = 0; } else if ((ff = FoFiType1C::load(fileName))) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); delete ff; } else { cidToGIDMap = NULL; nCIDs = 0; } ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile, cidToGIDMap, nCIDs); if (!ret) { gfree(cidToGIDMap); } return ret; } SplashFontFile *SplashFTFontEngine::loadOpenTypeCFFFont(SplashFontFileID *idA, char *fileName, GBool deleteFile, int *codeToGID, int codeToGIDLen) { FoFiTrueType *ff; GBool isCID; int *cidToGIDMap; int nCIDs; SplashFontFile *ret; cidToGIDMap = NULL; nCIDs = 0; isCID = gFalse; if (!codeToGID) { if (!useCIDs) { if ((ff = FoFiTrueType::load(fileName))) { if (ff->isOpenTypeCFF()) { cidToGIDMap = ff->getCIDToGIDMap(&nCIDs); } delete ff; } } } ret = SplashFTFontFile::loadCIDFont(this, idA, fileName, deleteFile, codeToGID ? codeToGID : cidToGIDMap, codeToGID ? codeToGIDLen : nCIDs); if (!ret) { gfree(cidToGIDMap); } return ret; } SplashFontFile *SplashFTFontEngine::loadTrueTypeFont(SplashFontFileID *idA, char *fileName, int fontNum, GBool deleteFile, int *codeToGID, int codeToGIDLen) { FoFiTrueType *ff; GString *tmpFileName; FILE *tmpFile; SplashFontFile *ret; //~ this should use fontNum to load the correct font if (!(ff = FoFiTrueType::load(fileName))) { return NULL; } tmpFileName = NULL; if (!openTempFile(&tmpFileName, &tmpFile, "wb", NULL)) { delete ff; return NULL; } ff->writeTTF(&fileWrite, tmpFile); delete ff; fclose(tmpFile); ret = SplashFTFontFile::loadTrueTypeFont(this, idA, tmpFileName->getCString(), fontNum, gTrue, codeToGID, codeToGIDLen); if (ret) { if (deleteFile) { unlink(fileName); } } else { unlink(tmpFileName->getCString()); } delete tmpFileName; return ret; } #endif // HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H xpdf-3.03/splash/SplashBitmap.h0000644000076400007640000000372611622305345015755 0ustar dereknderekn//======================================================================== // // SplashBitmap.h // //======================================================================== #ifndef SPLASHBITMAP_H #define SPLASHBITMAP_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include "SplashTypes.h" //------------------------------------------------------------------------ // SplashBitmap //------------------------------------------------------------------------ class SplashBitmap { public: // Create a new bitmap. It will have x pixels in // color mode . Rows will be padded out to a multiple of // bytes. If is false, the bitmap will be stored // upside-down, i.e., with the last row first in memory. SplashBitmap(int widthA, int heightA, int rowPad, SplashColorMode modeA, GBool alphaA, GBool topDown = gTrue); ~SplashBitmap(); int getWidth() { return width; } int getHeight() { return height; } int getRowSize() { return rowSize; } int getAlphaRowSize() { return width; } SplashColorMode getMode() { return mode; } SplashColorPtr getDataPtr() { return data; } Guchar *getAlphaPtr() { return alpha; } SplashError writePNMFile(char *fileName); SplashError writePNMFile(FILE *f); SplashError writeAlphaPGMFile(char *fileName); void getPixel(int x, int y, SplashColorPtr pixel); Guchar getAlpha(int x, int y); // Caller takes ownership of the bitmap data. The SplashBitmap // object is no longer valid -- the next call should be to the // destructor. SplashColorPtr takeData(); private: int width, height; // size of bitmap int rowSize; // size of one row of data, in bytes // - negative for bottom-up bitmaps SplashColorMode mode; // color mode SplashColorPtr data; // pointer to row zero of the color data Guchar *alpha; // pointer to row zero of the alpha data // (always top-down) friend class Splash; }; #endif xpdf-3.03/splash/SplashT1Font.h0000644000076400007640000000246611622305345015654 0ustar dereknderekn//======================================================================== // // SplashT1Font.h // //======================================================================== #ifndef SPLASHT1FONT_H #define SPLASHT1FONT_H #include #if HAVE_T1LIB_H #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "SplashFont.h" class SplashT1FontFile; //------------------------------------------------------------------------ // SplashT1Font //------------------------------------------------------------------------ class SplashT1Font: public SplashFont { public: SplashT1Font(SplashT1FontFile *fontFileA, SplashCoord *matA, SplashCoord *textMatA); virtual ~SplashT1Font(); // Munge xFrac and yFrac before calling SplashFont::getGlyph. virtual GBool getGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Rasterize a glyph. The and values are the same // as described for getGlyph. virtual GBool makeGlyph(int c, int xFrac, int yFrac, SplashGlyphBitmap *bitmap); // Return the path for a glyph. virtual SplashPath *getGlyphPath(int c); private: int t1libID; // t1lib font ID int outlineID; // t1lib font ID for glyph outlines float size; float outlineSize; // size for glyph outlines float outlineMul; }; #endif // HAVE_T1LIB_H #endif xpdf-3.03/install-sh0000755000076400007640000001272111622305345013722 0ustar dereknderekn#! /bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd="$cpprog" shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd="$stripprog" shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "install: no input file specified" exit 1 else true fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d $dst ]; then instcmd=: else instcmd=mkdir fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f $src -o -d $src ] then true else echo "install: $src does not exist" exit 1 fi if [ x"$dst" = x ] then echo "install: no destination specified" exit 1 else true fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d $dst ] then dst="$dst"/`basename $src` else true fi fi ## this sed command emulates the dirname command dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-${defaultIFS}}" oIFS="${IFS}" # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` IFS="${oIFS}" pathcomp='' while [ $# -ne 0 ] ; do pathcomp="${pathcomp}${1}" shift if [ ! -d "${pathcomp}" ] ; then $mkdirprog "${pathcomp}" else true fi pathcomp="${pathcomp}/" done fi if [ x"$dir_arg" != x ] then $doit $instcmd $dst && if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename $dst` else dstfile=`basename $dst $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename $dst` else true fi # Make a temp file name in the proper directory. dsttmp=$dstdir/#inst.$$# # Move or copy the file name to the temp name $doit $instcmd $src $dsttmp && trap "rm -f ${dsttmp}" 0 && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && # Now rename the file to the real destination. $doit $rmcmd -f $dstdir/$dstfile && $doit $mvcmd $dsttmp $dstdir/$dstfile fi && exit 0 xpdf-3.03/ms_make.bat0000644000076400007640000002237311622305345014026 0ustar derekndereknset CC=cl set CFLAGS=/DWIN32 /I.. /I..\goo /I..\fofi /I..\splash /O2 /nologo set CXX=cl set CXXFLAGS=%CFLAGS% /TP set LIBPROG=lib set LINKFLAGS=/MT /nologo copy aconf-win32.h aconf.h cd goo %CXX% %CXXFLAGS% /c GHash.cc %CXX% %CXXFLAGS% /c GList.cc %CXX% %CXXFLAGS% /c GString.cc %CXX% %CXXFLAGS% /c gmem.cc %CXX% %CXXFLAGS% /c gmempp.cc %CXX% %CXXFLAGS% /c gfile.cc %CC% %CFLAGS% /c parseargs.c %LIBPROG% /nologo /out:Goo.lib GHash.obj GList.obj GString.obj gmempp.obj gfile.obj gmem.obj parseargs.obj cd ..\fofi %CXX% %CXXFLAGS% /c FoFiBase.cc %CXX% %CXXFLAGS% /c FoFiEncodings.cc %CXX% %CXXFLAGS% /c FoFiIdentifier.cc %CXX% %CXXFLAGS% /c FoFiTrueType.cc %CXX% %CXXFLAGS% /c FoFiType1.cc %CXX% %CXXFLAGS% /c FoFiType1C.cc %LIBPROG% /nologo /out:fofi.lib FoFiBase.obj FoFiEncodings.obj FoFiIdentifier.obj FoFiTrueType.obj FoFiType1.obj FoFiType1C.obj cd ..\xpdf %CXX% %CXXFLAGS% /c Annot.cc %CXX% %CXXFLAGS% /c Array.cc %CXX% %CXXFLAGS% /c BuiltinFont.cc %CXX% %CXXFLAGS% /c BuiltinFontTables.cc %CXX% %CXXFLAGS% /c CMap.cc %CXX% %CXXFLAGS% /c Catalog.cc %CXX% %CXXFLAGS% /c CharCodeToUnicode.cc %CXX% %CXXFLAGS% /c Decrypt.cc %CXX% %CXXFLAGS% /c Dict.cc %CXX% %CXXFLAGS% /c Error.cc %CXX% %CXXFLAGS% /c FontEncodingTables.cc %CXX% %CXXFLAGS% /c Function.cc %CXX% %CXXFLAGS% /c Gfx.cc %CXX% %CXXFLAGS% /c GfxFont.cc %CXX% %CXXFLAGS% /c GfxState.cc %CXX% %CXXFLAGS% /c GlobalParams.cc %CXX% %CXXFLAGS% /c ImageOutputDev.cc %CXX% %CXXFLAGS% /c JArithmeticDecoder.cc %CXX% %CXXFLAGS% /c JBIG2Stream.cc %CXX% %CXXFLAGS% /c JPXStream.cc %CXX% %CXXFLAGS% /c Lexer.cc %CXX% %CXXFLAGS% /c Link.cc %CXX% %CXXFLAGS% /c NameToCharCode.cc %CXX% %CXXFLAGS% /c Object.cc %CXX% %CXXFLAGS% /c OptionalContent.cc %CXX% %CXXFLAGS% /c Outline.cc %CXX% %CXXFLAGS% /c OutputDev.cc %CXX% %CXXFLAGS% /c PDFDoc.cc %CXX% %CXXFLAGS% /c PDFDocEncoding.cc %CXX% %CXXFLAGS% /c PSOutputDev.cc %CXX% %CXXFLAGS% /c PSTokenizer.cc %CXX% %CXXFLAGS% /c Page.cc %CXX% %CXXFLAGS% /c Parser.cc %CXX% %CXXFLAGS% /c PreScanOutputDev.cc %CXX% %CXXFLAGS% /c SecurityHandler.cc %CXX% %CXXFLAGS% /c Stream.cc %CXX% %CXXFLAGS% /c TextOutputDev.cc %CXX% %CXXFLAGS% /c UnicodeMap.cc %CXX% %CXXFLAGS% /c UnicodeTypeTable.cc %CXX% %CXXFLAGS% /c XRef.cc %CXX% %CXXFLAGS% /c pdftops.cc %CXX% %CXXFLAGS% /c pdftotext.cc %CXX% %CXXFLAGS% /c pdfinfo.cc %CXX% %CXXFLAGS% /c pdffonts.cc %CXX% %CXXFLAGS% /c pdfdetach.cc %CXX% %CXXFLAGS% /c pdfimages.cc rem --- Comment out this line, and uncomment the other pdftops build line rem (see below) to build pdftops with the Splash rasterizer. rem You'll also need to define HAVE_SPLASH in aconf-win32.h. %CXX% %LINKFLAGS% /Fepdftops.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSOutputDev.obj PSTokenizer.obj PreScanOutputDev.obj SecurityHandler.obj Stream.obj UnicodeMap.obj XRef.obj pdftops.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib %CXX% %LINKFLAGS% /Fepdftotext.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj Stream.obj TextOutputDev.obj UnicodeMap.obj UnicodeTypeTable.obj XRef.obj pdftotext.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib %CXX% %LINKFLAGS% /Fepdfinfo.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj Stream.obj UnicodeMap.obj XRef.obj pdfinfo.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib %CXX% %LINKFLAGS% /Fepdffonts.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj Stream.obj UnicodeMap.obj XRef.obj pdffonts.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib %CXX% %LINKFLAGS% /Fepdfdetach.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj Stream.obj UnicodeMap.obj XRef.obj pdfdetach.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib %CXX% %LINKFLAGS% /Fepdfimages.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj ImageOutputDev.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj Stream.obj UnicodeMap.obj XRef.obj pdfimages.obj ..\fofi\fofi.lib ..\goo\Goo.lib shell32.lib user32.lib gdi32.lib advapi32.lib cd .. rem --- This part will only work if you have FreeType installed --- set FT2DIR=..\freetype-2.4.6 set CXXFLAGS=%CXXFLAGS% /I%FT2DIR%\include cd splash %CXX% %CXXFLAGS% /c Splash.cc %CXX% %CXXFLAGS% /c SplashBitmap.cc %CXX% %CXXFLAGS% /c SplashClip.cc %CXX% %CXXFLAGS% /c SplashFTFont.cc %CXX% %CXXFLAGS% /c SplashFTFontEngine.cc %CXX% %CXXFLAGS% /c SplashFTFontFile.cc %CXX% %CXXFLAGS% /c SplashFont.cc %CXX% %CXXFLAGS% /c SplashFontEngine.cc %CXX% %CXXFLAGS% /c SplashFontFile.cc %CXX% %CXXFLAGS% /c SplashFontFileID.cc %CXX% %CXXFLAGS% /c SplashPath.cc %CXX% %CXXFLAGS% /c SplashPattern.cc %CXX% %CXXFLAGS% /c SplashScreen.cc %CXX% %CXXFLAGS% /c SplashState.cc %CXX% %CXXFLAGS% /c SplashT1Font.cc %CXX% %CXXFLAGS% /c SplashT1FontEngine.cc %CXX% %CXXFLAGS% /c SplashT1FontFile.cc %CXX% %CXXFLAGS% /c SplashXPath.cc %CXX% %CXXFLAGS% /c SplashXPathScanner.cc %LIBPROG% /nologo /out:splash.lib Splash.obj SplashBitmap.obj SplashClip.obj SplashFTFont.obj SplashFTFontEngine.obj SplashFTFontFile.obj SplashFont.obj SplashFontEngine.obj SplashFontFile.obj SplashFontFileID.obj SplashPath.obj SplashPattern.obj SplashScreen.obj SplashState.obj SplashT1Font.obj SplashT1FontEngine.obj SplashT1FontFile.obj SplashXPath.obj SplashXPathScanner.obj cd ..\xpdf %CXX% %CXXFLAGS% /c SplashOutputDev.cc %CXX% %CXXFLAGS% /c pdftoppm.cc %CXX% %LINKFLAGS% /Fepdftoppm.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSTokenizer.obj SecurityHandler.obj SplashOutputDev.obj Stream.obj UnicodeMap.obj UnicodeTypeTable.obj XRef.obj pdftoppm.obj ..\splash\splash.lib ..\fofi\fofi.lib ..\goo\Goo.lib %FT2DIR%\freetype2.lib shell32.lib user32.lib gdi32.lib advapi32.lib rem --- Uncomment this line, and comment out the other pdftops build rem line (see above) to build pdftops with the Splash rasterizer. rem You'll also need to define HAVE_SPLASH in aconf-win32.h. rem %CXX% %LINKFLAGS% /Fepdftops.exe Annot.obj Array.obj BuiltinFont.obj BuiltinFontTables.obj Catalog.obj CharCodeToUnicode.obj CMap.obj Decrypt.obj Dict.obj Error.obj FontEncodingTables.obj Function.obj Gfx.obj GfxFont.obj GfxState.obj GlobalParams.obj JArithmeticDecoder.obj JBIG2Stream.obj JPXStream.obj Lexer.obj Link.obj NameToCharCode.obj Object.obj OptionalContent.obj Outline.obj OutputDev.obj Page.obj Parser.obj PDFDoc.obj PDFDocEncoding.obj PSOutputDev.obj PSTokenizer.obj PreScanOutputDev.obj SecurityHandler.obj SplashOutputDev.obj Stream.obj UnicodeMap.obj XRef.obj pdftops.obj ..\splash\splash.lib ..\fofi\fofi.lib ..\goo\Goo.lib %FT2DIR%\freetype2.lib shell32.lib user32.lib gdi32.lib advapi32.lib cd .. xpdf-3.03/dj_make.bat0000644000076400007640000000531611622305345014002 0ustar derekndereknset CC=gcc set CFLAGS=-g -O2 -I.. -I..\fofi -I..\goo set CXX=gpp set CXXFLAGS=%CFLAGS% set LIBPROG=ar copy aconf-dj.h aconf.h cd goo %CXX% %CXXFLAGS% -c GHash.cc %CXX% %CXXFLAGS% -c GList.cc %CXX% %CXXFLAGS% -c GString.cc %CXX% %CXXFLAGS% -c gmem.cc %CXX% %CXXFLAGS% -c gmempp.cc %CXX% %CXXFLAGS% -c gfile.cc %CC% %CFLAGS% -c parseargs.c del libGoo.a %LIBPROG% -rc libGoo.a GHash.o GList.o GString.o gmempp.o gfile.o gmem.o parseargs.o cd ..\fofi %CXX% %CXXFLAGS% -c FoFiBase.cc %CXX% %CXXFLAGS% -c FoFiEncodings.cc %CXX% %CXXFLAGS% -c FoFiIdentifier.cc %CXX% %CXXFLAGS% -c FoFiTrueType.cc %CXX% %CXXFLAGS% -c FoFiType1.cc %CXX% %CXXFLAGS% -c FoFiType1C.cc %LIBPROG% -rc libfofi.a FoFiBase.o FoFiEncodings.o FoFiIdentifier.o FoFiTrueType.o FoFiType1.o FoFiType1C.o cd ..\xpdf del *.o %CXX% %CXXFLAGS% -c Annot.cc %CXX% %CXXFLAGS% -c Array.cc %CXX% %CXXFLAGS% -c BuiltinFont.cc %CXX% %CXXFLAGS% -c BuiltinFontTables.cc %CXX% %CXXFLAGS% -c CMap.cc %CXX% %CXXFLAGS% -c Catalog.cc %CXX% %CXXFLAGS% -c CharCodeToUnicode.cc %CXX% %CXXFLAGS% -c Decrypt.cc %CXX% %CXXFLAGS% -c Dict.cc %CXX% %CXXFLAGS% -c Error.cc %CXX% %CXXFLAGS% -c FontEncodingTables.cc %CXX% %CXXFLAGS% -c Function.cc %CXX% %CXXFLAGS% -c Gfx.cc %CXX% %CXXFLAGS% -c GfxFont.cc %CXX% %CXXFLAGS% -c GfxState.cc %CXX% %CXXFLAGS% -c GlobalParams.cc %CXX% %CXXFLAGS% -c ImageOutputDev.cc %CXX% %CXXFLAGS% -c JArithmeticDecoder.cc %CXX% %CXXFLAGS% -c JBIG2Stream.cc %CXX% %CXXFLAGS% -c JPXStream.cc %CXX% %CXXFLAGS% -c Lexer.cc %CXX% %CXXFLAGS% -c Link.cc %CXX% %CXXFLAGS% -c NameToCharCode.cc %CXX% %CXXFLAGS% -c Object.cc %CXX% %CXXFLAGS% -c OptionalContent.cc %CXX% %CXXFLAGS% -c Outline.cc %CXX% %CXXFLAGS% -c OutputDev.cc %CXX% %CXXFLAGS% -c PDFDoc.cc %CXX% %CXXFLAGS% -c PDFDocEncoding.cc %CXX% %CXXFLAGS% -c PSOutputDev.cc %CXX% %CXXFLAGS% -c PSTokenizer.cc %CXX% %CXXFLAGS% -c Page.cc %CXX% %CXXFLAGS% -c Parser.cc %CXX% %CXXFLAGS% -c SecurityHandler.cc %CXX% %CXXFLAGS% -c Stream.cc %CXX% %CXXFLAGS% -c TextOutputDev.cc %CXX% %CXXFLAGS% -c UnicodeMap.cc %CXX% %CXXFLAGS% -c UnicodeTypeTable.cc %CXX% %CXXFLAGS% -c XRef.cc del libxpdf.a %LIBPROG% -rc libxpdf.a *.o %CXX% %CXXFLAGS% -o pdftops.exe pdftops.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a %CXX% %CXXFLAGS% -o pdftotext.exe pdftotext.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a %CXX% %CXXFLAGS% -o pdfinfo.exe pdfinfo.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a %CXX% %CXXFLAGS% -o pdffonts.exe pdffonts.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a %CXX% %CXXFLAGS% -o pdfdetach.exe pdfdetach.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a %CXX% %CXXFLAGS% -o pdfimages.exe pdfimages.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a cd .. xpdf-3.03/fofi/0000755000076400007640000000000011622305345012636 5ustar derekndereknxpdf-3.03/fofi/FoFiBase.h0000644000076400007640000000250011622305345014422 0ustar dereknderekn//======================================================================== // // FoFiBase.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FOFIBASE_H #define FOFIBASE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" //------------------------------------------------------------------------ typedef void (*FoFiOutputFunc)(void *stream, const char *data, int len); //------------------------------------------------------------------------ // FoFiBase //------------------------------------------------------------------------ class FoFiBase { public: virtual ~FoFiBase(); protected: FoFiBase(char *fileA, int lenA, GBool freeFileDataA); static char *readFile(char *fileName, int *fileLen); // S = signed / U = unsigned // 8/16/32/Var = word length, in bytes // BE = big endian int getS8(int pos, GBool *ok); int getU8(int pos, GBool *ok); int getS16BE(int pos, GBool *ok); int getU16BE(int pos, GBool *ok); int getS32BE(int pos, GBool *ok); Guint getU32BE(int pos, GBool *ok); Guint getU32LE(int pos, GBool *ok); Guint getUVarBE(int pos, int size, GBool *ok); GBool checkRegion(int pos, int size); Guchar *fileData; Guchar *file; int len; GBool freeFileData; }; #endif xpdf-3.03/fofi/FoFiTrueType.cc0000644000076400007640000020551011622305345015475 0ustar dereknderekn//======================================================================== // // FoFiTrueType.cc // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #if HAVE_STD_SORT #include #endif #include "gtypes.h" #include "gmem.h" #include "GString.h" #include "GHash.h" #include "FoFiType1C.h" #include "FoFiTrueType.h" // // Terminology // ----------- // // character code = number used as an element of a text string // // character name = glyph name = name for a particular glyph within a // font // // glyph index = GID = position (within some internal table in the font) // where the instructions to draw a particular glyph are // stored // // Type 1 fonts // ------------ // // Type 1 fonts contain: // // Encoding: array of glyph names, maps char codes to glyph names // // Encoding[charCode] = charName // // CharStrings: dictionary of instructions, keyed by character names, // maps character name to glyph data // // CharStrings[charName] = glyphData // // TrueType fonts // -------------- // // TrueType fonts contain: // // 'cmap' table: mapping from character code to glyph index; there may // be multiple cmaps in a TrueType font // // cmap[charCode] = gid // // 'post' table: mapping from glyph index to glyph name // // post[gid] = glyphName // // Type 42 fonts // ------------- // // Type 42 fonts contain: // // Encoding: array of glyph names, maps char codes to glyph names // // Encoding[charCode] = charName // // CharStrings: dictionary of glyph indexes, keyed by character names, // maps character name to glyph index // // CharStrings[charName] = gid // //------------------------------------------------------------------------ #define ttcfTag 0x74746366 //------------------------------------------------------------------------ struct TrueTypeTable { Guint tag; Guint checksum; int offset; int origOffset; int len; }; struct TrueTypeCmap { int platform; int encoding; int offset; int len; int fmt; }; struct TrueTypeLoca { int idx; int origOffset; int newOffset; int len; }; #define cmapTag 0x636d6170 #define glyfTag 0x676c7966 #define headTag 0x68656164 #define hheaTag 0x68686561 #define hmtxTag 0x686d7478 #define locaTag 0x6c6f6361 #define nameTag 0x6e616d65 #define os2Tag 0x4f532f32 #define postTag 0x706f7374 #ifdef HAVE_STD_SORT struct cmpTrueTypeLocaOffsetFunctor { bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) { if (loca1.origOffset == loca2.origOffset) { return loca1.idx < loca2.idx; } return loca1.origOffset < loca2.origOffset; } }; struct cmpTrueTypeLocaIdxFunctor { bool operator()(const TrueTypeLoca &loca1, const TrueTypeLoca &loca2) { return loca1.idx < loca2.idx; } }; struct cmpTrueTypeTableTagFunctor { bool operator()(const TrueTypeTable &tab1, const TrueTypeTable &tab2) { return tab1.tag < tab2.tag; } }; #else // HAVE_STD_SORT static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; if (loca1->origOffset == loca2->origOffset) { return loca1->idx - loca2->idx; } return loca1->origOffset - loca2->origOffset; } static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { TrueTypeLoca *loca1 = (TrueTypeLoca *)p1; TrueTypeLoca *loca2 = (TrueTypeLoca *)p2; return loca1->idx - loca2->idx; } static int cmpTrueTypeTableTag(const void *p1, const void *p2) { TrueTypeTable *tab1 = (TrueTypeTable *)p1; TrueTypeTable *tab2 = (TrueTypeTable *)p2; return (int)tab1->tag - (int)tab2->tag; } #endif // HAVE_STD_SORT //------------------------------------------------------------------------ struct T42Table { const char *tag; // 4-byte tag GBool required; // required by the TrueType spec? }; // TrueType tables to be embedded in Type 42 fonts. // NB: the table names must be in alphabetical order here. #define nT42Tables 11 static T42Table t42Tables[nT42Tables] = { { "cvt ", gTrue }, { "fpgm", gTrue }, { "glyf", gTrue }, { "head", gTrue }, { "hhea", gTrue }, { "hmtx", gTrue }, { "loca", gTrue }, { "maxp", gTrue }, { "prep", gTrue }, { "vhea", gFalse }, { "vmtx", gFalse } }; #define t42HeadTable 3 #define t42LocaTable 6 #define t42GlyfTable 2 #define t42VheaTable 9 #define t42VmtxTable 10 //------------------------------------------------------------------------ // Glyph names in some arbitrary standard order that Apple uses for // their TrueType fonts. static const char *macGlyphNames[258] = { ".notdef", "null", "CR", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quotesingle", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "grave", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "Adieresis", "Aring", "Ccedilla", "Eacute", "Ntilde", "Odieresis", "Udieresis", "aacute", "agrave", "acircumflex", "adieresis", "atilde", "aring", "ccedilla", "eacute", "egrave", "ecircumflex", "edieresis", "iacute", "igrave", "icircumflex", "idieresis", "ntilde", "oacute", "ograve", "ocircumflex", "odieresis", "otilde", "uacute", "ugrave", "ucircumflex", "udieresis", "dagger", "degree", "cent", "sterling", "section", "bullet", "paragraph", "germandbls", "registered", "copyright", "trademark", "acute", "dieresis", "notequal", "AE", "Oslash", "infinity", "plusminus", "lessequal", "greaterequal", "yen", "mu1", "partialdiff", "summation", "product", "pi", "integral", "ordfeminine", "ordmasculine", "Ohm", "ae", "oslash", "questiondown", "exclamdown", "logicalnot", "radical", "florin", "approxequal", "increment", "guillemotleft", "guillemotright", "ellipsis", "nbspace", "Agrave", "Atilde", "Otilde", "OE", "oe", "endash", "emdash", "quotedblleft", "quotedblright", "quoteleft", "quoteright", "divide", "lozenge", "ydieresis", "Ydieresis", "fraction", "currency", "guilsinglleft", "guilsinglright", "fi", "fl", "daggerdbl", "periodcentered", "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex", "Ecircumflex", "Aacute", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Oacute", "Ocircumflex", "applelogo", "Ograve", "Uacute", "Ucircumflex", "Ugrave", "dotlessi", "circumflex", "tilde", "overscore", "breve", "dotaccent", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "Lslash", "lslash", "Scaron", "scaron", "Zcaron", "zcaron", "brokenbar", "Eth", "eth", "Yacute", "yacute", "Thorn", "thorn", "minus", "multiply", "onesuperior", "twosuperior", "threesuperior", "onehalf", "onequarter", "threequarters", "franc", "Gbreve", "gbreve", "Idot", "Scedilla", "scedilla", "Cacute", "cacute", "Ccaron", "ccaron", "dmacron" }; //------------------------------------------------------------------------ // FoFiTrueType //------------------------------------------------------------------------ FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) { FoFiTrueType *ff; ff = new FoFiTrueType(fileA, lenA, gFalse); if (!ff->parsedOk) { delete ff; return NULL; } return ff; } FoFiTrueType *FoFiTrueType::load(char *fileName) { FoFiTrueType *ff; char *fileA; int lenA; if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { return NULL; } ff = new FoFiTrueType(fileA, lenA, gTrue); if (!ff->parsedOk) { delete ff; return NULL; } return ff; } FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA): FoFiBase(fileA, lenA, freeFileDataA) { tables = NULL; nTables = 0; cmaps = NULL; nCmaps = 0; nameToGID = NULL; parsedOk = gFalse; parse(); } FoFiTrueType::~FoFiTrueType() { gfree(tables); gfree(cmaps); if (nameToGID) { delete nameToGID; } } int FoFiTrueType::getNumCmaps() { return nCmaps; } int FoFiTrueType::getCmapPlatform(int i) { return cmaps[i].platform; } int FoFiTrueType::getCmapEncoding(int i) { return cmaps[i].encoding; } int FoFiTrueType::findCmap(int platform, int encoding) { int i; for (i = 0; i < nCmaps; ++i) { if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) { return i; } } return -1; } int FoFiTrueType::mapCodeToGID(int i, int c) { int gid; int segCnt, segEnd, segStart, segDelta, segOffset; int cmapFirst, cmapLen; int pos, a, b, m; GBool ok; if (i < 0 || i >= nCmaps) { return 0; } ok = gTrue; pos = cmaps[i].offset; switch (cmaps[i].fmt) { case 0: if (c < 0 || c >= cmaps[i].len - 6) { return 0; } gid = getU8(cmaps[i].offset + 6 + c, &ok); break; case 4: segCnt = getU16BE(pos + 6, &ok) / 2; a = -1; b = segCnt - 1; segEnd = getU16BE(pos + 14 + 2*b, &ok); if (c > segEnd) { // malformed font -- the TrueType spec requires the last segEnd // to be 0xffff return 0; } // invariant: seg[a].end < code <= seg[b].end while (b - a > 1 && ok) { m = (a + b) / 2; segEnd = getU16BE(pos + 14 + 2*m, &ok); if (segEnd < c) { a = m; } else { b = m; } } segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok); segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok); segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok); if (c < segStart) { return 0; } if (segOffset == 0) { gid = (c + segDelta) & 0xffff; } else { gid = getU16BE(pos + 16 + 6*segCnt + 2*b + segOffset + 2 * (c - segStart), &ok); if (gid != 0) { gid = (gid + segDelta) & 0xffff; } } break; case 6: cmapFirst = getU16BE(pos + 6, &ok); cmapLen = getU16BE(pos + 8, &ok); if (c < cmapFirst || c >= cmapFirst + cmapLen) { return 0; } gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok); break; default: return 0; } if (!ok) { return 0; } return gid; } int FoFiTrueType::mapNameToGID(char *name) { if (!nameToGID) { return 0; } return nameToGID->lookupInt(name); } GBool FoFiTrueType::getCFFBlock(char **start, int *length) { int i; if (!openTypeCFF) { return gFalse; } i = seekTable("CFF "); if (!checkRegion(tables[i].offset, tables[i].len)) { return gFalse; } *start = (char *)file + tables[i].offset; *length = tables[i].len; return gTrue; } int *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { char *start; int length; FoFiType1C *ff; int *map; *nCIDs = 0; if (!getCFFBlock(&start, &length)) { return NULL; } if (!(ff = FoFiType1C::make(start, length))) { return NULL; } map = ff->getCIDToGIDMap(nCIDs); delete ff; return map; } int FoFiTrueType::getEmbeddingRights() { int i, fsType; GBool ok; if ((i = seekTable("OS/2")) < 0) { return 4; } ok = gTrue; fsType = getU16BE(tables[i].offset + 8, &ok); if (!ok) { return 4; } if (fsType & 0x0008) { return 2; } if (fsType & 0x0004) { return 1; } if (fsType & 0x0002) { return 0; } return 3; } void FoFiTrueType::getFontMatrix(double *mat) { char *start; int length; FoFiType1C *ff; if (!getCFFBlock(&start, &length)) { return; } if (!(ff = FoFiType1C::make(start, length))) { return; } ff->getFontMatrix(mat); delete ff; } void FoFiTrueType::convertToType42(char *psName, char **encoding, int *codeToGID, FoFiOutputFunc outputFunc, void *outputStream) { GString *buf; int maxUsedGlyph; GBool ok; if (openTypeCFF) { return; } // write the header ok = gTrue; buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", (double)getS32BE(0, &ok) / 65536.0); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; // begin the font dictionary (*outputFunc)(outputStream, "10 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 42 def\n", 17); (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", bbox[0], bbox[1], bbox[2], bbox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); // write the guts of the dictionary cvtEncoding(encoding, outputFunc, outputStream); cvtCharStrings(encoding, codeToGID, outputFunc, outputStream); cvtSfnts(outputFunc, outputStream, NULL, gFalse, &maxUsedGlyph); // end the dictionary and define the font (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); } void FoFiTrueType::convertToType1(char *psName, const char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream) { char *start; int length; FoFiType1C *ff; if (!getCFFBlock(&start, &length)) { return; } if (!(ff = FoFiType1C::make(start, length))) { return; } ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); delete ff; } void FoFiTrueType::convertToCIDType2(char *psName, int *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { GString *buf; int cid, maxUsedGlyph; GBool ok; int i, j, k; if (openTypeCFF) { return; } // write the header ok = gTrue; buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n", (double)getS32BE(0, &ok) / 65536.0); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; // begin the font dictionary (*outputFunc)(outputStream, "20 dict begin\n", 14); (*outputFunc)(outputStream, "/CIDFontName /", 14); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); (*outputFunc)(outputStream, "/FontType 42 def\n", 17); (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); (*outputFunc)(outputStream, " end def\n", 10); (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); if (cidMap) { buf = GString::format("/CIDCount {0:d} def\n", nCIDs); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; if (nCIDs > 32767) { (*outputFunc)(outputStream, "/CIDMap [", 9); for (i = 0; i < nCIDs; i += 32768 - 16) { (*outputFunc)(outputStream, "<\n", 2); for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { (*outputFunc)(outputStream, " ", 2); for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { cid = cidMap[i+j+k]; buf = GString::format("{0:02x}{1:02x}", (cid >> 8) & 0xff, cid & 0xff); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "\n", 1); } (*outputFunc)(outputStream, " >", 3); } (*outputFunc)(outputStream, "\n", 1); (*outputFunc)(outputStream, "] def\n", 6); } else { (*outputFunc)(outputStream, "/CIDMap <\n", 10); for (i = 0; i < nCIDs; i += 16) { (*outputFunc)(outputStream, " ", 2); for (j = 0; j < 16 && i+j < nCIDs; ++j) { cid = cidMap[i+j]; buf = GString::format("{0:02x}{1:02x}", (cid >> 8) & 0xff, cid & 0xff); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "\n", 1); } (*outputFunc)(outputStream, "> def\n", 6); } } else { // direct mapping - just fill the string(s) with s[i]=i buf = GString::format("/CIDCount {0:d} def\n", nGlyphs); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; if (nGlyphs > 32767) { (*outputFunc)(outputStream, "/CIDMap [\n", 10); for (i = 0; i < nGlyphs; i += 32767) { j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n", i); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add" " 255 and put\n", i); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, " } for\n", 8); } (*outputFunc)(outputStream, "] def\n", 6); } else { buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, " 2 copy dup 2 mul exch -8 bitshift put\n", 42); (*outputFunc)(outputStream, " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); (*outputFunc)(outputStream, " } for\n", 8); (*outputFunc)(outputStream, "def\n", 4); } } (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", bbox[0], bbox[1], bbox[2], bbox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); (*outputFunc)(outputStream, " end readonly def\n", 19); // write the guts of the dictionary cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics, &maxUsedGlyph); // end the dictionary and define the font (*outputFunc)(outputStream, "CIDFontName currentdict end /CIDFont defineresource pop\n", 56); } void FoFiTrueType::convertToCIDType0(char *psName, int *cidMap, int nCIDs, FoFiOutputFunc outputFunc, void *outputStream) { char *start; int length; FoFiType1C *ff; if (!getCFFBlock(&start, &length)) { return; } if (!(ff = FoFiType1C::make(start, length))) { return; } ff->convertToCIDType0(psName, cidMap, nCIDs, outputFunc, outputStream); delete ff; } void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { GString *buf; GString *sfntsName; int maxUsedGlyph, n, i, j; if (openTypeCFF) { return; } // write the Type 42 sfnts array sfntsName = (new GString(psName))->append("_sfnts"); cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics, &maxUsedGlyph); delete sfntsName; // write the descendant Type 42 fonts // (The following is a kludge: nGlyphs is the glyph count from the // maxp table; maxUsedGlyph is the max glyph number that has a // non-zero-length description, from the loca table. The problem is // that some TrueType font subsets fail to change the glyph count, // i.e., nGlyphs is much larger than maxUsedGlyph+1, which results // in an unnecessarily huge Type 0 font. But some other PDF files // have fonts with only zero or one used glyph, and a content stream // that refers to one of the unused glyphs -- this results in PS // errors if we simply use maxUsedGlyph+1 for the Type 0 font. So // we compromise by always defining at least 256 glyphs.) if (cidMap) { n = nCIDs; } else if (nGlyphs > maxUsedGlyph + 256) { if (maxUsedGlyph <= 255) { n = 256; } else { n = maxUsedGlyph + 1; } } else { n = nGlyphs; } for (i = 0; i < n; i += 256) { (*outputFunc)(outputStream, "10 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, (int)strlen(psName)); buf = GString::format("_{0:02x} def\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FontType 42 def\n", 17); (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n", bbox[0], bbox[1], bbox[2], bbox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); (*outputFunc)(outputStream, "/sfnts ", 7); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, "_sfnts def\n", 11); (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); for (j = 0; j < 256 && i+j < n; ++j) { buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "readonly def\n", 13); (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); for (j = 0; j < 256 && i+j < n; ++j) { buf = GString::format("/c{0:02x} {1:d} def\n", j, cidMap ? cidMap[i+j] : i+j); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "end readonly def\n", 17); (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); } // write the Type 0 parent font (*outputFunc)(outputStream, "16 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 0 def\n", 16); (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); (*outputFunc)(outputStream, "/Encoding [\n", 12); for (i = 0; i < n; i += 256) { buf = GString::format("{0:d}\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); (*outputFunc)(outputStream, "/FDepVector [\n", 14); for (i = 0; i < n; i += 256) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, psName, (int)strlen(psName)); buf = GString::format("_{0:02x} findfont\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); } void FoFiTrueType::convertToType0(char *psName, int *cidMap, int nCIDs, FoFiOutputFunc outputFunc, void *outputStream) { char *start; int length; FoFiType1C *ff; if (!getCFFBlock(&start, &length)) { return; } if (!(ff = FoFiType1C::make(start, length))) { return; } ff->convertToType0(psName, cidMap, nCIDs, outputFunc, outputStream); delete ff; } void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, void *outputStream, char *name, int *codeToGID) { // this substitute cmap table maps char code ffff to glyph 0, // with tables for MacRoman and MS Unicode static char cmapTab[44] = { 0, 0, // table version number 0, 2, // number of encoding tables 0, 1, // platform ID 0, 0, // encoding ID 0, 0, 0, 20, // offset of subtable 0, 3, // platform ID 0, 1, // encoding ID 0, 0, 0, 20, // offset of subtable 0, 4, // subtable format 0, 24, // subtable length 0, 0, // subtable version 0, 2, // segment count * 2 0, 2, // 2 * 2 ^ floor(log2(segCount)) 0, 0, // floor(log2(segCount)) 0, 0, // 2*segCount - 2*2^floor(log2(segCount)) (char)0xff, (char)0xff, // endCount[0] 0, 0, // reserved (char)0xff, (char)0xff, // startCount[0] 0, 1, // idDelta[0] 0, 0 // idRangeOffset[0] }; static char nameTab[8] = { 0, 0, // format 0, 0, // number of name records 0, 6, // offset to start of string storage 0, 0 // pad to multiple of four bytes }; static char postTab[32] = { 0, 1, 0, 0, // format 0, 0, 0, 0, // italic angle 0, 0, // underline position 0, 0, // underline thickness 0, 0, 0, 0, // fixed pitch 0, 0, 0, 0, // min Type 42 memory 0, 0, 0, 0, // max Type 42 memory 0, 0, 0, 0, // min Type 1 memory 0, 0, 0, 0 // max Type 1 memory }; static char os2Tab[86] = { 0, 1, // version 0, 1, // xAvgCharWidth 0x01, (char)0x90, // usWeightClass 0, 5, // usWidthClass 0, 0, // fsType 0, 0, // ySubscriptXSize 0, 0, // ySubscriptYSize 0, 0, // ySubscriptXOffset 0, 0, // ySubscriptYOffset 0, 0, // ySuperscriptXSize 0, 0, // ySuperscriptYSize 0, 0, // ySuperscriptXOffset 0, 0, // ySuperscriptYOffset 0, 0, // yStrikeoutSize 0, 0, // yStrikeoutPosition 0, 0, // sFamilyClass 0, 0, 0, 0, 0, // panose 0, 0, 0, 0, 0, 0, 0, 0, 0, // ulUnicodeRange1 0, 0, 0, 0, // ulUnicodeRange2 0, 0, 0, 0, // ulUnicodeRange3 0, 0, 0, 0, // ulUnicodeRange4 0, 0, 0, 0, // achVendID 0, 0, // fsSelection 0, 0, // usFirstCharIndex 0, 0, // usLastCharIndex 0, 0, // sTypoAscender 0, 0, // sTypoDescender 0, 0, // sTypoLineGap 0x20, 0x00, // usWinAscent 0x20, 0x00, // usWinDescent 0, 0, 0, 1, // ulCodePageRange1 0, 0, 0, 0 // ulCodePageRange2 }; GBool missingCmap, missingName, missingPost, missingOS2; GBool unsortedLoca, emptyCmap, badCmapLen, abbrevHMTX; int nZeroLengthTables, nBogusTables; int nHMetrics, advWidth, lsb; TrueTypeLoca *locaTable; TrueTypeTable *newTables; char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab; int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next; int newHHEALen, newHMTXLen; Guint locaChecksum, glyfChecksum, fileChecksum; char *tableDir; char locaBuf[4], checksumBuf[4]; GBool ok; Guint t; int pos, i, j, k, n; if (openTypeCFF) { return; } // check for missing tables // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver // will embed a PCL TrueType font with the pitch field set to zero, // which apparently causes divide-by-zero errors. As far as I can // tell, the only important field in the OS/2 table is // xAvgCharWidth.) missingCmap = (cmapIdx = seekTable("cmap")) < 0; missingName = seekTable("name") < 0; missingPost = seekTable("post") < 0; missingOS2 = seekTable("OS/2") < 0; // read the loca table, check to see if it's sorted locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); unsortedLoca = gFalse; i = seekTable("loca"); pos = tables[i].offset; ok = gTrue; for (i = 0; i <= nGlyphs; ++i) { if (locaFmt) { locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); } else { locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); } if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) { unsortedLoca = gTrue; } // glyph descriptions must be at least 12 bytes long (nContours, // xMin, yMin, xMax, yMax, instructionLength - two bytes each); // invalid glyph descriptions (even if they're never used) make // Windows choke, so we work around that problem here (ideally, // this would parse the glyph descriptions in the glyf table and // remove any that were invalid, but this quick test is a decent // start) if (i > 0 && locaTable[i].origOffset - locaTable[i-1].origOffset > 0 && locaTable[i].origOffset - locaTable[i-1].origOffset < 12) { locaTable[i-1].origOffset = locaTable[i].origOffset; unsortedLoca = gTrue; } locaTable[i].idx = i; } // check for zero-length tables and bogus tags nZeroLengthTables = nBogusTables = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len == 0) { ++nZeroLengthTables; if (tables[i].tag == cmapTag) { missingCmap = gTrue; } else if (tables[i].tag == nameTag) { missingName = gTrue; } else if (tables[i].tag == postTag) { missingPost = gTrue; } else if (tables[i].tag == os2Tag) { missingOS2 = gTrue; } } else if (!(tables[i].tag & 0xe0000000) || !(tables[i].tag & 0x00e00000) || !(tables[i].tag & 0x0000e000) || !(tables[i].tag & 0x000000e0)) { // tags where any of the bytes are < 0x20 are probably bogus // (the TrueType spec uses ASCII sequences for tags) -- this // catches problems where the number of tables given in the // header is too large, and so gibberish data is read at the end // of the table directory ++nBogusTables; } } // check for an empty cmap table or an incorrect cmap table length emptyCmap = badCmapLen = gFalse; cmapLen = 0; // make gcc happy if (!missingCmap) { if (nCmaps == 0) { emptyCmap = gTrue; } else { cmapLen = cmaps[0].offset + cmaps[0].len; for (i = 1; i < nCmaps; ++i) { if (cmaps[i].offset + cmaps[i].len > cmapLen) { cmapLen = cmaps[i].offset + cmaps[i].len; } } cmapLen -= tables[cmapIdx].offset; if (cmapLen > tables[cmapIdx].len) { badCmapLen = gTrue; } } } // check for an abbreviated hmtx table (this is completely legal, // but confuses the Microsoft PCL5 printer driver, which generates // embedded fonts with the pitch field set to zero) i = seekTable("hhea"); nHMetrics = getU16BE(tables[i].offset + 34, &ok); abbrevHMTX = nHMetrics < nGlyphs; // if nothing is broken, just write the TTF file as is if (!missingCmap && !missingName && !missingPost && !missingOS2 && !unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && nBogusTables == 0 && !name && !codeToGID) { (*outputFunc)(outputStream, (char *)file, len); goto done1; } // sort the 'loca' table: some (non-compliant) fonts have // out-of-order loca tables; in order to correctly handle the case // where (compliant) fonts have empty entries in the middle of the // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, // and idx as its secondary key (ensuring that adjacent entries with // the same pos value remain in the same order) glyfLen = 0; // make gcc happy if (unsortedLoca) { #if HAVE_STD_SORT std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaOffsetFunctor()); #else qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaOffset); #endif for (i = 0; i < nGlyphs; ++i) { locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; } locaTable[nGlyphs].len = 0; #if HAVE_STD_SORT std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor()); #else qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); #endif // if the last entry in the loca is not the max offset (size of // the glyf table), something is wrong -- work around the problem // by forcing the last sorted entry to have a zero length locaTable[nGlyphs].len = 0; pos = 0; for (i = 0; i <= nGlyphs; ++i) { locaTable[i].newOffset = pos; pos += locaTable[i].len; if (pos & 3) { pos += 4 - (pos & 3); } } glyfLen = pos; } // compute checksums for the loca and glyf tables locaChecksum = glyfChecksum = 0; if (unsortedLoca) { if (locaFmt) { for (j = 0; j <= nGlyphs; ++j) { locaChecksum += locaTable[j].newOffset; } } else { for (j = 0; j <= nGlyphs; j += 2) { locaChecksum += locaTable[j].newOffset << 16; if (j + 1 <= nGlyphs) { locaChecksum += locaTable[j+1].newOffset; } } } pos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { n = locaTable[j].len; if (n > 0) { k = locaTable[j].origOffset; if (checkRegion(pos + k, n)) { glyfChecksum += computeTableChecksum(file + pos + k, n); } } } } // construct the new name table if (name) { n = (int)strlen(name); newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3; newNameTab = (char *)gmalloc(newNameLen); memset(newNameTab, 0, newNameLen); newNameTab[0] = 0; // format selector newNameTab[1] = 0; newNameTab[2] = 0; // number of name records newNameTab[3] = 4; newNameTab[4] = 0; // offset to start of string storage newNameTab[5] = 6 + 4*12; next = 0; for (i = 0; i < 4; ++i) { newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft newNameTab[6 + i*12 + 1] = 3; newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode newNameTab[6 + i*12 + 3] = 1; newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English newNameTab[6 + i*12 + 5] = 0x09; newNameTab[6 + i*12 + 6] = 0; // name ID newNameTab[6 + i*12 + 7] = i + 1; newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff); newNameTab[6 + i*12 + 10] = next >> 8; // string offset newNameTab[6 + i*12 + 11] = next & 0xff; if (i+1 == 2) { memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14); next += 14; } else { for (j = 0; j < n; ++j) { newNameTab[6 + 4*12 + next + 2*j] = 0; newNameTab[6 + 4*12 + next + 2*j + 1] = name[j]; } next += 2*n; } } } else { newNameLen = 0; newNameTab = NULL; } // construct the new cmap table if (codeToGID) { newCmapLen = 44 + 256 * 2; newCmapTab = (char *)gmalloc(newCmapLen); newCmapTab[0] = 0; // table version number = 0 newCmapTab[1] = 0; newCmapTab[2] = 0; // number of encoding tables = 1 newCmapTab[3] = 1; newCmapTab[4] = 0; // platform ID = Microsoft newCmapTab[5] = 3; newCmapTab[6] = 0; // encoding ID = Unicode newCmapTab[7] = 1; newCmapTab[8] = 0; // offset of subtable newCmapTab[9] = 0; newCmapTab[10] = 0; newCmapTab[11] = 12; newCmapTab[12] = 0; // subtable format = 4 newCmapTab[13] = 4; newCmapTab[14] = 0x02; // subtable length newCmapTab[15] = 0x20; newCmapTab[16] = 0; // subtable version = 0 newCmapTab[17] = 0; newCmapTab[18] = 0; // segment count * 2 newCmapTab[19] = 4; newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount)) newCmapTab[21] = 4; newCmapTab[22] = 0; // floor(log2(segCount)) newCmapTab[23] = 1; newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount)) newCmapTab[25] = 0; newCmapTab[26] = 0x00; // endCount[0] newCmapTab[27] = (char)0xff; newCmapTab[28] = (char)0xff; // endCount[1] newCmapTab[29] = (char)0xff; newCmapTab[30] = 0; // reserved newCmapTab[31] = 0; newCmapTab[32] = 0x00; // startCount[0] newCmapTab[33] = 0x00; newCmapTab[34] = (char)0xff; // startCount[1] newCmapTab[35] = (char)0xff; newCmapTab[36] = 0; // idDelta[0] newCmapTab[37] = 0; newCmapTab[38] = 0; // idDelta[1] newCmapTab[39] = 1; newCmapTab[40] = 0; // idRangeOffset[0] newCmapTab[41] = 4; newCmapTab[42] = 0; // idRangeOffset[1] newCmapTab[43] = 0; for (i = 0; i < 256; ++i) { if (codeToGID[i] < 0) { //~ this may not be correct - we want this character to never be //~ displayed, but mapping it to the notdef glyph may result in //~ little boxes being displayed newCmapTab[44 + 2*i] = 0; newCmapTab[44 + 2*i + 1] = 0; } else { newCmapTab[44 + 2*i] = codeToGID[i] >> 8; newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff; } } } else { newCmapLen = 0; newCmapTab = NULL; } // generate the new hmtx table and the updated hhea table if (abbrevHMTX) { i = seekTable("hhea"); pos = tables[i].offset; newHHEALen = 36; newHHEATab = (char *)gmalloc(newHHEALen); for (i = 0; i < newHHEALen; ++i) { newHHEATab[i] = getU8(pos++, &ok); } newHHEATab[34] = nGlyphs >> 8; newHHEATab[35] = nGlyphs & 0xff; i = seekTable("hmtx"); pos = tables[i].offset; newHMTXLen = 4 * nGlyphs; newHMTXTab = (char *)gmalloc(newHMTXLen); advWidth = 0; for (i = 0; i < nHMetrics; ++i) { advWidth = getU16BE(pos, &ok); lsb = getU16BE(pos + 2, &ok); pos += 4; newHMTXTab[4*i ] = advWidth >> 8; newHMTXTab[4*i + 1] = advWidth & 0xff; newHMTXTab[4*i + 2] = lsb >> 8; newHMTXTab[4*i + 3] = lsb & 0xff; } for (; i < nGlyphs; ++i) { lsb = getU16BE(pos, &ok); pos += 2; newHMTXTab[4*i ] = advWidth >> 8; newHMTXTab[4*i + 1] = advWidth & 0xff; newHMTXTab[4*i + 2] = lsb >> 8; newHMTXTab[4*i + 3] = lsb & 0xff; } } else { newHHEATab = newHMTXTab = NULL; newHHEALen = newHMTXLen = 0; // make gcc happy } // construct the new table directory: // - keep all original tables with non-zero length // - fix the cmap table's length, if necessary // - add missing tables // - sort the table by tag // - compute new table positions, including 4-byte alignment // - (re)compute table checksums nNewTables = nTables - nZeroLengthTables - nBogusTables + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); j = 0; for (i = 0; i < nTables; ++i) { if (tables[i].len > 0 && (tables[i].tag & 0xe0000000) && (tables[i].tag & 0x00e00000) && (tables[i].tag & 0x0000e000) && (tables[i].tag & 0x000000e0)) { newTables[j] = tables[i]; newTables[j].origOffset = tables[i].offset; if (checkRegion(tables[i].offset, tables[i].len)) { newTables[j].checksum = computeTableChecksum(file + tables[i].offset, tables[i].len); if (tables[i].tag == headTag) { // don't include the file checksum newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok); } } if (newTables[j].tag == cmapTag && codeToGID) { newTables[j].len = newCmapLen; newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); } else if (newTables[j].tag == cmapTag && emptyCmap) { newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, sizeof(cmapTab)); newTables[j].len = sizeof(cmapTab); } else if (newTables[j].tag == cmapTag && badCmapLen) { newTables[j].len = cmapLen; } else if (newTables[j].tag == locaTag && unsortedLoca) { newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2); newTables[j].checksum = locaChecksum; } else if (newTables[j].tag == glyfTag && unsortedLoca) { newTables[j].len = glyfLen; newTables[j].checksum = glyfChecksum; } else if (newTables[j].tag == nameTag && name) { newTables[j].len = newNameLen; newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, newNameLen); } else if (newTables[j].tag == hheaTag && abbrevHMTX) { newTables[j].len = newHHEALen; newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab, newHHEALen); } else if (newTables[j].tag == hmtxTag && abbrevHMTX) { newTables[j].len = newHMTXLen; newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab, newHMTXLen); } ++j; } } if (missingCmap) { newTables[j].tag = cmapTag; if (codeToGID) { newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab, newCmapLen); newTables[j].len = newCmapLen; } else { newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab, sizeof(cmapTab)); newTables[j].len = sizeof(cmapTab); } ++j; } if (missingName) { newTables[j].tag = nameTag; if (name) { newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab, newNameLen); newTables[j].len = newNameLen; } else { newTables[j].checksum = computeTableChecksum((Guchar *)nameTab, sizeof(nameTab)); newTables[j].len = sizeof(nameTab); } ++j; } if (missingPost) { newTables[j].tag = postTag; newTables[j].checksum = computeTableChecksum((Guchar *)postTab, sizeof(postTab)); newTables[j].len = sizeof(postTab); ++j; } if (missingOS2) { newTables[j].tag = os2Tag; newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab, sizeof(os2Tab)); newTables[j].len = sizeof(os2Tab); ++j; } #if HAVE_STD_SORT std::sort(newTables, newTables + nNewTables, cmpTrueTypeTableTagFunctor()); #else qsort(newTables, nNewTables, sizeof(TrueTypeTable), &cmpTrueTypeTableTag); #endif pos = 12 + nNewTables * 16; for (i = 0; i < nNewTables; ++i) { newTables[i].offset = pos; pos += newTables[i].len; if (pos & 3) { pos += 4 - (pos & 3); } } // write the table directory tableDir = (char *)gmalloc(12 + nNewTables * 16); tableDir[0] = 0x00; // sfnt version tableDir[1] = 0x01; tableDir[2] = 0x00; tableDir[3] = 0x00; tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables tableDir[5] = (char)(nNewTables & 0xff); for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ; t = 1 << (4 + i); tableDir[6] = (char)((t >> 8) & 0xff); // searchRange tableDir[7] = (char)(t & 0xff); tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector tableDir[9] = (char)(i & 0xff); t = nNewTables * 16 - t; tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift tableDir[11] = (char)(t & 0xff); pos = 12; for (i = 0; i < nNewTables; ++i) { tableDir[pos ] = (char)(newTables[i].tag >> 24); tableDir[pos+ 1] = (char)(newTables[i].tag >> 16); tableDir[pos+ 2] = (char)(newTables[i].tag >> 8); tableDir[pos+ 3] = (char) newTables[i].tag; tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24); tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16); tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8); tableDir[pos+ 7] = (char) newTables[i].checksum; tableDir[pos+ 8] = (char)(newTables[i].offset >> 24); tableDir[pos+ 9] = (char)(newTables[i].offset >> 16); tableDir[pos+10] = (char)(newTables[i].offset >> 8); tableDir[pos+11] = (char) newTables[i].offset; tableDir[pos+12] = (char)(newTables[i].len >> 24); tableDir[pos+13] = (char)(newTables[i].len >> 16); tableDir[pos+14] = (char)(newTables[i].len >> 8); tableDir[pos+15] = (char) newTables[i].len; pos += 16; } (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16); // compute the file checksum fileChecksum = computeTableChecksum((Guchar *)tableDir, 12 + nNewTables * 16); for (i = 0; i < nNewTables; ++i) { fileChecksum += newTables[i].checksum; } fileChecksum = 0xb1b0afba - fileChecksum; // write the tables for (i = 0; i < nNewTables; ++i) { if (newTables[i].tag == headTag) { if (checkRegion(newTables[i].origOffset, newTables[i].len)) { (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8); checksumBuf[0] = fileChecksum >> 24; checksumBuf[1] = fileChecksum >> 16; checksumBuf[2] = fileChecksum >> 8; checksumBuf[3] = fileChecksum; (*outputFunc)(outputStream, checksumBuf, 4); (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset + 12, newTables[i].len - 12); } else { for (j = 0; j < newTables[i].len; ++j) { (*outputFunc)(outputStream, "\0", 1); } } } else if (newTables[i].tag == cmapTag && codeToGID) { (*outputFunc)(outputStream, newCmapTab, newTables[i].len); } else if (newTables[i].tag == cmapTag && missingCmap) { (*outputFunc)(outputStream, cmapTab, newTables[i].len); } else if (newTables[i].tag == nameTag && name) { (*outputFunc)(outputStream, newNameTab, newTables[i].len); } else if (newTables[i].tag == nameTag && missingName) { (*outputFunc)(outputStream, nameTab, newTables[i].len); } else if (newTables[i].tag == postTag && missingPost) { (*outputFunc)(outputStream, postTab, newTables[i].len); } else if (newTables[i].tag == os2Tag && missingOS2) { (*outputFunc)(outputStream, os2Tab, newTables[i].len); } else if (newTables[i].tag == hheaTag && abbrevHMTX) { (*outputFunc)(outputStream, newHHEATab, newTables[i].len); } else if (newTables[i].tag == hmtxTag && abbrevHMTX) { (*outputFunc)(outputStream, newHMTXTab, newTables[i].len); } else if (newTables[i].tag == locaTag && unsortedLoca) { for (j = 0; j <= nGlyphs; ++j) { if (locaFmt) { locaBuf[0] = (char)(locaTable[j].newOffset >> 24); locaBuf[1] = (char)(locaTable[j].newOffset >> 16); locaBuf[2] = (char)(locaTable[j].newOffset >> 8); locaBuf[3] = (char) locaTable[j].newOffset; (*outputFunc)(outputStream, locaBuf, 4); } else { locaBuf[0] = (char)(locaTable[j].newOffset >> 9); locaBuf[1] = (char)(locaTable[j].newOffset >> 1); (*outputFunc)(outputStream, locaBuf, 2); } } } else if (newTables[i].tag == glyfTag && unsortedLoca) { pos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { n = locaTable[j].len; if (n > 0) { k = locaTable[j].origOffset; if (checkRegion(pos + k, n)) { (*outputFunc)(outputStream, (char *)file + pos + k, n); } else { for (k = 0; k < n; ++k) { (*outputFunc)(outputStream, "\0", 1); } } if ((k = locaTable[j].len & 3)) { (*outputFunc)(outputStream, "\0\0\0\0", 4 - k); } } } } else { if (checkRegion(newTables[i].origOffset, newTables[i].len)) { (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, newTables[i].len); } else { for (j = 0; j < newTables[i].len; ++j) { (*outputFunc)(outputStream, "\0", 1); } } } if (newTables[i].len & 3) { (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3)); } } gfree(newHMTXTab); gfree(newHHEATab); gfree(newCmapTab); gfree(newNameTab); gfree(tableDir); gfree(newTables); done1: gfree(locaTable); } void FoFiTrueType::cvtEncoding(char **encoding, FoFiOutputFunc outputFunc, void *outputStream) { const char *name; GString *buf; int i; (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); if (encoding) { for (i = 0; i < 256; ++i) { if (!(name = encoding[i])) { name = ".notdef"; } buf = GString::format("dup {0:d} /", i); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, name, (int)strlen(name)); (*outputFunc)(outputStream, " put\n", 5); } } else { for (i = 0; i < 256; ++i) { buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } } (*outputFunc)(outputStream, "readonly def\n", 13); } void FoFiTrueType::cvtCharStrings(char **encoding, int *codeToGID, FoFiOutputFunc outputFunc, void *outputStream) { char *name; GString *buf; char buf2[16]; int i, k; // always define '.notdef' (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); // if there's no 'cmap' table, punt if (nCmaps == 0) { goto err; } // map char name to glyph index: // 1. use encoding to map name to char code // 2. use codeToGID to map char code to glyph index // N.B. We do this in reverse order because font subsets can have // weird encodings that use the same character name twice, and // the first definition is probably the one we want. k = 0; // make gcc happy for (i = 255; i >= 0; --i) { if (encoding) { name = encoding[i]; } else { sprintf(buf2, "c%02x", i); name = buf2; } if (name && strcmp(name, ".notdef")) { k = codeToGID[i]; // note: Distiller (maybe Adobe's PS interpreter in general) // doesn't like TrueType fonts that have CharStrings entries // which point to nonexistent glyphs, hence the (k < nGlyphs) // test if (k > 0 && k < nGlyphs) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, name, (int)strlen(name)); buf = GString::format(" {0:d} def\n", k); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } } } err: (*outputFunc)(outputStream, "end readonly def\n", 17); } void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, void *outputStream, GString *name, GBool needVerticalMetrics, int *maxUsedGlyph) { Guchar headData[54]; TrueTypeLoca *locaTable; Guchar *locaData; TrueTypeTable newTables[nT42Tables]; Guchar tableDir[12 + nT42Tables*16]; GBool ok; Guint checksum; int nNewTables; int glyfTableLen, length, pos, glyfPos, i, j, k; Guchar vheaTab[36] = { 0, 1, 0, 0, // table version number 0, 0, // ascent 0, 0, // descent 0, 0, // reserved 0, 0, // max advance height 0, 0, // min top side bearing 0, 0, // min bottom side bearing 0, 0, // y max extent 0, 0, // caret slope rise 0, 1, // caret slope run 0, 0, // caret offset 0, 0, // reserved 0, 0, // reserved 0, 0, // reserved 0, 0, // reserved 0, 0, // metric data format 0, 1 // number of advance heights in vmtx table }; Guchar *vmtxTab; GBool needVhea, needVmtx; int advance; // construct the 'head' table, zero out the font checksum i = seekTable("head"); pos = tables[i].offset; if (!checkRegion(pos, 54)) { return; } memcpy(headData, file + pos, 54); headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0; // check for a bogus loca format field in the 'head' table // (I've encountered fonts with loca format set to 0x0100 instead of 0x0001) if (locaFmt != 0 && locaFmt != 1) { headData[50] = 0; headData[51] = 1; } // read the original 'loca' table, pad entries out to 4 bytes, and // sort it into proper order -- some (non-compliant) fonts have // out-of-order loca tables; in order to correctly handle the case // where (compliant) fonts have empty entries in the middle of the // table, cmpTrueTypeLocaOffset uses offset as its primary sort key, // and idx as its secondary key (ensuring that adjacent entries with // the same pos value remain in the same order) locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca)); i = seekTable("loca"); pos = tables[i].offset; i = seekTable("glyf"); glyfTableLen = tables[i].len; ok = gTrue; for (i = 0; i <= nGlyphs; ++i) { locaTable[i].idx = i; if (locaFmt) { locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok); } else { locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok); } if (locaTable[i].origOffset > glyfTableLen) { locaTable[i].origOffset = glyfTableLen; } } #if HAVE_STD_SORT std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaOffsetFunctor()); #else qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaOffset); #endif for (i = 0; i < nGlyphs; ++i) { locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset; } locaTable[nGlyphs].len = 0; #if HAVE_STD_SORT std::sort(locaTable, locaTable + nGlyphs + 1, cmpTrueTypeLocaIdxFunctor()); #else qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); #endif pos = 0; *maxUsedGlyph = -1; for (i = 0; i <= nGlyphs; ++i) { locaTable[i].newOffset = pos; pos += locaTable[i].len; if (pos & 3) { pos += 4 - (pos & 3); } if (locaTable[i].len > 0) { *maxUsedGlyph = i; } } // construct the new 'loca' table locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2)); for (i = 0; i <= nGlyphs; ++i) { pos = locaTable[i].newOffset; if (locaFmt) { locaData[4*i ] = (Guchar)(pos >> 24); locaData[4*i+1] = (Guchar)(pos >> 16); locaData[4*i+2] = (Guchar)(pos >> 8); locaData[4*i+3] = (Guchar) pos; } else { locaData[2*i ] = (Guchar)(pos >> 9); locaData[2*i+1] = (Guchar)(pos >> 1); } } // count the number of tables nNewTables = 0; for (i = 0; i < nT42Tables; ++i) { if (t42Tables[i].required || seekTable(t42Tables[i].tag) >= 0) { ++nNewTables; } } vmtxTab = NULL; // make gcc happy advance = 0; // make gcc happy if (needVerticalMetrics) { needVhea = seekTable("vhea") < 0; needVmtx = seekTable("vmtx") < 0; if (needVhea || needVmtx) { i = seekTable("head"); advance = getU16BE(tables[i].offset + 18, &ok); // units per em if (needVhea) { ++nNewTables; } if (needVmtx) { ++nNewTables; } } } // construct the new table headers, including table checksums // (pad each table out to a multiple of 4 bytes) pos = 12 + nNewTables*16; k = 0; for (i = 0; i < nT42Tables; ++i) { length = -1; checksum = 0; // make gcc happy if (i == t42HeadTable) { length = 54; checksum = computeTableChecksum(headData, 54); } else if (i == t42LocaTable) { length = (nGlyphs + 1) * (locaFmt ? 4 : 2); checksum = computeTableChecksum(locaData, length); } else if (i == t42GlyfTable) { length = 0; checksum = 0; glyfPos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { length += locaTable[j].len; if (length & 3) { length += 4 - (length & 3); } if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { checksum += computeTableChecksum(file + glyfPos + locaTable[j].origOffset, locaTable[j].len); } } } else { if ((j = seekTable(t42Tables[i].tag)) >= 0) { length = tables[j].len; if (checkRegion(tables[j].offset, length)) { checksum = computeTableChecksum(file + tables[j].offset, length); } } else if (needVerticalMetrics && i == t42VheaTable) { vheaTab[10] = advance / 256; // max advance height vheaTab[11] = advance % 256; length = sizeof(vheaTab); checksum = computeTableChecksum(vheaTab, length); } else if (needVerticalMetrics && i == t42VmtxTable) { length = 4 + (nGlyphs - 1) * 2; vmtxTab = (Guchar *)gmalloc(length); vmtxTab[0] = advance / 256; vmtxTab[1] = advance % 256; for (j = 2; j < length; j += 2) { vmtxTab[j] = 0; vmtxTab[j+1] = 0; } checksum = computeTableChecksum(vmtxTab, length); } else if (t42Tables[i].required) { //~ error(-1, "Embedded TrueType font is missing a required table ('%s')", //~ t42Tables[i].tag); length = 0; checksum = 0; } } if (length >= 0) { newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) | ((t42Tables[i].tag[1] & 0xff) << 16) | ((t42Tables[i].tag[2] & 0xff) << 8) | (t42Tables[i].tag[3] & 0xff); newTables[k].checksum = checksum; newTables[k].offset = pos; newTables[k].len = length; pos += length; if (pos & 3) { pos += 4 - (length & 3); } ++k; } } // construct the table directory tableDir[0] = 0x00; // sfnt version tableDir[1] = 0x01; tableDir[2] = 0x00; tableDir[3] = 0x00; tableDir[4] = 0; // numTables tableDir[5] = nNewTables; tableDir[6] = 0; // searchRange tableDir[7] = (Guchar)128; tableDir[8] = 0; // entrySelector tableDir[9] = 3; tableDir[10] = 0; // rangeShift tableDir[11] = (Guchar)(16 * nNewTables - 128); pos = 12; for (i = 0; i < nNewTables; ++i) { tableDir[pos ] = (Guchar)(newTables[i].tag >> 24); tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16); tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8); tableDir[pos+ 3] = (Guchar) newTables[i].tag; tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24); tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16); tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8); tableDir[pos+ 7] = (Guchar) newTables[i].checksum; tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24); tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16); tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8); tableDir[pos+11] = (Guchar) newTables[i].offset; tableDir[pos+12] = (Guchar)(newTables[i].len >> 24); tableDir[pos+13] = (Guchar)(newTables[i].len >> 16); tableDir[pos+14] = (Guchar)(newTables[i].len >> 8); tableDir[pos+15] = (Guchar) newTables[i].len; pos += 16; } // compute the font checksum and store it in the head table checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); for (i = 0; i < nNewTables; ++i) { checksum += newTables[i].checksum; } checksum = 0xb1b0afba - checksum; // because the TrueType spec says so headData[ 8] = (Guchar)(checksum >> 24); headData[ 9] = (Guchar)(checksum >> 16); headData[10] = (Guchar)(checksum >> 8); headData[11] = (Guchar) checksum; // start the sfnts array if (name) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, name->getCString(), name->getLength()); (*outputFunc)(outputStream, " [\n", 3); } else { (*outputFunc)(outputStream, "/sfnts [\n", 9); } // write the table directory dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); // write the tables for (i = 0; i < nNewTables; ++i) { if (i == t42HeadTable) { dumpString(headData, 54, outputFunc, outputStream); } else if (i == t42LocaTable) { length = (nGlyphs + 1) * (locaFmt ? 4 : 2); dumpString(locaData, length, outputFunc, outputStream); } else if (i == t42GlyfTable) { glyfPos = tables[seekTable("glyf")].offset; for (j = 0; j < nGlyphs; ++j) { if (locaTable[j].len > 0 && checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) { dumpString(file + glyfPos + locaTable[j].origOffset, locaTable[j].len, outputFunc, outputStream); } } } else { // length == 0 means the table is missing and the error was // already reported during the construction of the table // headers if ((length = newTables[i].len) > 0) { if ((j = seekTable(t42Tables[i].tag)) >= 0 && checkRegion(tables[j].offset, tables[j].len)) { dumpString(file + tables[j].offset, tables[j].len, outputFunc, outputStream); } else if (needVerticalMetrics && i == t42VheaTable) { dumpString(vheaTab, length, outputFunc, outputStream); } else if (needVerticalMetrics && i == t42VmtxTable) { dumpString(vmtxTab, length, outputFunc, outputStream); } } } } // end the sfnts array (*outputFunc)(outputStream, "] def\n", 6); gfree(locaData); gfree(locaTable); if (vmtxTab) { gfree(vmtxTab); } } void FoFiTrueType::dumpString(Guchar *s, int length, FoFiOutputFunc outputFunc, void *outputStream) { GString *buf; int pad, i, j; (*outputFunc)(outputStream, "<", 1); for (i = 0; i < length; i += 32) { for (j = 0; j < 32 && i+j < length; ++j) { buf = GString::format("{0:02x}", s[i+j] & 0xff); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (i % (65536 - 32) == 65536 - 64) { (*outputFunc)(outputStream, ">\n<", 3); } else if (i+32 < length) { (*outputFunc)(outputStream, "\n", 1); } } if (length & 3) { pad = 4 - (length & 3); for (i = 0; i < pad; ++i) { (*outputFunc)(outputStream, "00", 2); } } // add an extra zero byte because the Adobe Type 42 spec says so (*outputFunc)(outputStream, "00>\n", 4); } Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { Guint checksum, word; int i; checksum = 0; for (i = 0; i+3 < length; i += 4) { word = ((data[i ] & 0xff) << 24) + ((data[i+1] & 0xff) << 16) + ((data[i+2] & 0xff) << 8) + (data[i+3] & 0xff); checksum += word; } if (length & 3) { word = 0; i = length & ~3; switch (length & 3) { case 3: word |= (data[i+2] & 0xff) << 8; case 2: word |= (data[i+1] & 0xff) << 16; case 1: word |= (data[i ] & 0xff) << 24; break; } checksum += word; } return checksum; } void FoFiTrueType::parse() { Guint topTag; int pos, ver, i, j; parsedOk = gTrue; // look for a collection (TTC) topTag = getU32BE(0, &parsedOk); if (!parsedOk) { return; } if (topTag == ttcfTag) { pos = getU32BE(12, &parsedOk); if (!parsedOk) { return; } } else { pos = 0; } // check the sfnt version ver = getU32BE(pos, &parsedOk); if (!parsedOk) { return; } openTypeCFF = ver == 0x4f54544f; // 'OTTO' // read the table directory nTables = getU16BE(pos + 4, &parsedOk); if (!parsedOk) { return; } tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable)); pos += 12; j = 0; for (i = 0; i < nTables; ++i) { tables[j].tag = getU32BE(pos, &parsedOk); tables[j].checksum = getU32BE(pos + 4, &parsedOk); tables[j].offset = (int)getU32BE(pos + 8, &parsedOk); tables[j].len = (int)getU32BE(pos + 12, &parsedOk); if (tables[j].offset + tables[j].len >= tables[j].offset && tables[j].offset + tables[j].len <= len) { // ignore any bogus entries in the table directory ++j; } pos += 16; } nTables = j; if (!parsedOk) { return; } // check for tables that are required by both the TrueType spec and // the Type 42 spec if (seekTable("head") < 0 || seekTable("hhea") < 0 || seekTable("maxp") < 0 || seekTable("hmtx") < 0 || (!openTypeCFF && seekTable("loca") < 0) || (!openTypeCFF && seekTable("glyf") < 0) || (openTypeCFF && seekTable("CFF ") < 0)) { parsedOk = gFalse; return; } // read the cmaps if ((i = seekTable("cmap")) >= 0) { pos = tables[i].offset + 2; nCmaps = getU16BE(pos, &parsedOk); pos += 2; if (!parsedOk) { return; } cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap)); for (j = 0; j < nCmaps; ++j) { cmaps[j].platform = getU16BE(pos, &parsedOk); cmaps[j].encoding = getU16BE(pos + 2, &parsedOk); cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk); pos += 8; cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk); cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk); } if (!parsedOk) { return; } } else { nCmaps = 0; } // get the number of glyphs from the maxp table i = seekTable("maxp"); nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk); if (!parsedOk) { return; } // get the bbox and loca table format from the head table i = seekTable("head"); bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk); bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk); bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk); bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk); locaFmt = getS16BE(tables[i].offset + 50, &parsedOk); if (!parsedOk) { return; } // make sure the loca table is sane (correct length and entries are // in bounds) if (!openTypeCFF) { i = seekTable("loca"); if (tables[i].len < 0) { parsedOk = gFalse; return; } if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1; } for (j = 0; j <= nGlyphs; ++j) { if (locaFmt) { pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk); } else { pos = getU16BE(tables[i].offset + j*2, &parsedOk); } if (pos < 0 || pos > len) { parsedOk = gFalse; } } if (!parsedOk) { return; } } // read the post table readPostTable(); } void FoFiTrueType::readPostTable() { GString *name; int tablePos, postFmt, stringIdx, stringPos; GBool ok; int i, j, n, m; ok = gTrue; if ((i = seekTable("post")) < 0) { return; } tablePos = tables[i].offset; postFmt = getU32BE(tablePos, &ok); if (!ok) { goto err; } if (postFmt == 0x00010000) { nameToGID = new GHash(gTrue); for (i = 0; i < 258; ++i) { nameToGID->add(new GString(macGlyphNames[i]), i); } } else if (postFmt == 0x00020000) { nameToGID = new GHash(gTrue); n = getU16BE(tablePos + 32, &ok); if (!ok) { goto err; } if (n > nGlyphs) { n = nGlyphs; } stringIdx = 0; stringPos = tablePos + 34 + 2*n; for (i = 0; i < n; ++i) { j = getU16BE(tablePos + 34 + 2*i, &ok); if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); nameToGID->add(new GString(macGlyphNames[j]), i); } else { j -= 258; if (j != stringIdx) { for (stringIdx = 0, stringPos = tablePos + 34 + 2*n; stringIdx < j; ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ; if (!ok) { goto err; } } m = getU8(stringPos, &ok); if (!ok || !checkRegion(stringPos + 1, m)) { goto err; } name = new GString((char *)&file[stringPos + 1], m); nameToGID->removeInt(name); nameToGID->add(name, i); ++stringIdx; stringPos += 1 + m; } } } else if (postFmt == 0x00028000) { nameToGID = new GHash(gTrue); for (i = 0; i < nGlyphs; ++i) { j = getU8(tablePos + 32 + i, &ok); if (!ok) { goto err; } if (j < 258) { nameToGID->removeInt(macGlyphNames[j]); nameToGID->add(new GString(macGlyphNames[j]), i); } } } return; err: if (nameToGID) { delete nameToGID; nameToGID = NULL; } } int FoFiTrueType::seekTable(const char *tag) { Guint tagI; int i; tagI = ((tag[0] & 0xff) << 24) | ((tag[1] & 0xff) << 16) | ((tag[2] & 0xff) << 8) | (tag[3] & 0xff); for (i = 0; i < nTables; ++i) { if (tables[i].tag == tagI) { return i; } } return -1; } xpdf-3.03/fofi/Makefile.dep0000644000076400007640000000000011622305345015033 0ustar derekndereknxpdf-3.03/fofi/vms_make.com0000644000076400007640000000000011622305345015126 0ustar derekndereknxpdf-3.03/fofi/FoFiIdentifier.cc0000644000076400007640000003535411622305345016005 0ustar dereknderekn//======================================================================== // // FoFiIdentifier.cc // // Copyright 2009 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gtypes.h" #include "FoFiIdentifier.h" //------------------------------------------------------------------------ class Reader { public: virtual ~Reader() {} // Read one byte. Returns -1 if past EOF. virtual int getByte(int pos) = 0; // Read a big-endian unsigned 16-bit integer. Fills in *val and // returns true if successful. virtual GBool getU16BE(int pos, int *val) = 0; // Read a big-endian unsigned 32-bit integer. Fills in *val and // returns true if successful. virtual GBool getU32BE(int pos, Guint *val) = 0; // Read a little-endian unsigned 32-bit integer. Fills in *val and // returns true if successful. virtual GBool getU32LE(int pos, Guint *val) = 0; // Read a big-endian unsigned -byte integer, where 1 <= size // <= 4. Fills in *val and returns true if successful. virtual GBool getUVarBE(int pos, int size, Guint *val) = 0; // Compare against a string. Returns true if equal. virtual GBool cmp(int pos, const char *s) = 0; }; //------------------------------------------------------------------------ class MemReader: public Reader { public: static MemReader *make(char *bufA, int lenA); virtual ~MemReader(); virtual int getByte(int pos); virtual GBool getU16BE(int pos, int *val); virtual GBool getU32BE(int pos, Guint *val); virtual GBool getU32LE(int pos, Guint *val); virtual GBool getUVarBE(int pos, int size, Guint *val); virtual GBool cmp(int pos, const char *s); private: MemReader(char *bufA, int lenA); char *buf; int len; }; MemReader *MemReader::make(char *bufA, int lenA) { return new MemReader(bufA, lenA); } MemReader::MemReader(char *bufA, int lenA) { buf = bufA; len = lenA; } MemReader::~MemReader() { } int MemReader::getByte(int pos) { if (pos < 0 || pos >= len) { return -1; } return buf[pos] & 0xff; } GBool MemReader::getU16BE(int pos, int *val) { if (pos < 0 || pos > len - 2) { return gFalse; } *val = ((buf[pos] & 0xff) << 8) + (buf[pos+1] & 0xff); return gTrue; } GBool MemReader::getU32BE(int pos, Guint *val) { if (pos < 0 || pos > len - 4) { return gFalse; } *val = ((buf[pos] & 0xff) << 24) + ((buf[pos+1] & 0xff) << 16) + ((buf[pos+2] & 0xff) << 8) + (buf[pos+3] & 0xff); return gTrue; } GBool MemReader::getU32LE(int pos, Guint *val) { if (pos < 0 || pos > len - 4) { return gFalse; } *val = (buf[pos] & 0xff) + ((buf[pos+1] & 0xff) << 8) + ((buf[pos+2] & 0xff) << 16) + ((buf[pos+3] & 0xff) << 24); return gTrue; } GBool MemReader::getUVarBE(int pos, int size, Guint *val) { int i; if (size < 1 || size > 4 || pos < 0 || pos > len - size) { return gFalse; } *val = 0; for (i = 0; i < size; ++i) { *val = (*val << 8) + (buf[pos + i] & 0xff); } return gTrue; } GBool MemReader::cmp(int pos, const char *s) { int n; n = (int)strlen(s); if (pos < 0 || len < n || pos > len - n) { return gFalse; } return !memcmp(buf + pos, s, n); } //------------------------------------------------------------------------ class FileReader: public Reader { public: static FileReader *make(char *fileName); virtual ~FileReader(); virtual int getByte(int pos); virtual GBool getU16BE(int pos, int *val); virtual GBool getU32BE(int pos, Guint *val); virtual GBool getU32LE(int pos, Guint *val); virtual GBool getUVarBE(int pos, int size, Guint *val); virtual GBool cmp(int pos, const char *s); private: FileReader(FILE *fA); GBool fillBuf(int pos, int len); FILE *f; char buf[1024]; int bufPos, bufLen; }; FileReader *FileReader::make(char *fileName) { FILE *fA; if (!(fA = fopen(fileName, "rb"))) { return NULL; } return new FileReader(fA); } FileReader::FileReader(FILE *fA) { f = fA; bufPos = 0; bufLen = 0; } FileReader::~FileReader() { fclose(f); } int FileReader::getByte(int pos) { if (!fillBuf(pos, 1)) { return -1; } return buf[pos - bufPos] & 0xff; } GBool FileReader::getU16BE(int pos, int *val) { if (!fillBuf(pos, 2)) { return gFalse; } *val = ((buf[pos - bufPos] & 0xff) << 8) + (buf[pos - bufPos + 1] & 0xff); return gTrue; } GBool FileReader::getU32BE(int pos, Guint *val) { if (!fillBuf(pos, 4)) { return gFalse; } *val = ((buf[pos - bufPos] & 0xff) << 24) + ((buf[pos - bufPos + 1] & 0xff) << 16) + ((buf[pos - bufPos + 2] & 0xff) << 8) + (buf[pos - bufPos + 3] & 0xff); return gTrue; } GBool FileReader::getU32LE(int pos, Guint *val) { if (!fillBuf(pos, 4)) { return gFalse; } *val = (buf[pos - bufPos] & 0xff) + ((buf[pos - bufPos + 1] & 0xff) << 8) + ((buf[pos - bufPos + 2] & 0xff) << 16) + ((buf[pos - bufPos + 3] & 0xff) << 24); return gTrue; } GBool FileReader::getUVarBE(int pos, int size, Guint *val) { int i; if (size < 1 || size > 4 || !fillBuf(pos, size)) { return gFalse; } *val = 0; for (i = 0; i < size; ++i) { *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); } return gTrue; } GBool FileReader::cmp(int pos, const char *s) { int n; n = (int)strlen(s); if (!fillBuf(pos, n)) { return gFalse; } return !memcmp(buf - bufPos + pos, s, n); } GBool FileReader::fillBuf(int pos, int len) { if (pos < 0 || len < 0 || len > (int)sizeof(buf) || pos > INT_MAX - (int)sizeof(buf)) { return gFalse; } if (pos >= bufPos && pos + len <= bufPos + bufLen) { return gTrue; } if (fseek(f, pos, SEEK_SET)) { return gFalse; } bufPos = pos; bufLen = (int)fread(buf, 1, sizeof(buf), f); if (bufLen < len) { return gFalse; } return gTrue; } //------------------------------------------------------------------------ class StreamReader: public Reader { public: static StreamReader *make(int (*getCharA)(void *data), void *dataA); virtual ~StreamReader(); virtual int getByte(int pos); virtual GBool getU16BE(int pos, int *val); virtual GBool getU32BE(int pos, Guint *val); virtual GBool getU32LE(int pos, Guint *val); virtual GBool getUVarBE(int pos, int size, Guint *val); virtual GBool cmp(int pos, const char *s); private: StreamReader(int (*getCharA)(void *data), void *dataA); GBool fillBuf(int pos, int len); int (*getChar)(void *data); void *data; int streamPos; char buf[1024]; int bufPos, bufLen; }; StreamReader *StreamReader::make(int (*getCharA)(void *data), void *dataA) { return new StreamReader(getCharA, dataA); } StreamReader::StreamReader(int (*getCharA)(void *data), void *dataA) { getChar = getCharA; data = dataA; streamPos = 0; bufPos = 0; bufLen = 0; } StreamReader::~StreamReader() { } int StreamReader::getByte(int pos) { if (!fillBuf(pos, 1)) { return -1; } return buf[pos - bufPos] & 0xff; } GBool StreamReader::getU16BE(int pos, int *val) { if (!fillBuf(pos, 2)) { return gFalse; } *val = ((buf[pos - bufPos] & 0xff) << 8) + (buf[pos - bufPos + 1] & 0xff); return gTrue; } GBool StreamReader::getU32BE(int pos, Guint *val) { if (!fillBuf(pos, 4)) { return gFalse; } *val = ((buf[pos - bufPos] & 0xff) << 24) + ((buf[pos - bufPos + 1] & 0xff) << 16) + ((buf[pos - bufPos + 2] & 0xff) << 8) + (buf[pos - bufPos + 3] & 0xff); return gTrue; } GBool StreamReader::getU32LE(int pos, Guint *val) { if (!fillBuf(pos, 4)) { return gFalse; } *val = (buf[pos - bufPos] & 0xff) + ((buf[pos - bufPos + 1] & 0xff) << 8) + ((buf[pos - bufPos + 2] & 0xff) << 16) + ((buf[pos - bufPos + 3] & 0xff) << 24); return gTrue; } GBool StreamReader::getUVarBE(int pos, int size, Guint *val) { int i; if (size < 1 || size > 4 || !fillBuf(pos, size)) { return gFalse; } *val = 0; for (i = 0; i < size; ++i) { *val = (*val << 8) + (buf[pos - bufPos + i] & 0xff); } return gTrue; } GBool StreamReader::cmp(int pos, const char *s) { int n; n = (int)strlen(s); if (!fillBuf(pos, n)) { return gFalse; } return !memcmp(buf - bufPos + pos, s, n); } GBool StreamReader::fillBuf(int pos, int len) { int c; if (pos < 0 || len < 0 || len > (int)sizeof(buf) || pos > INT_MAX - (int)sizeof(buf)) { return gFalse; } if (pos < bufPos) { return gFalse; } // if requested region will not fit in the current buffer... if (pos + len > bufPos + (int)sizeof(buf)) { // if the start of the requested data is already in the buffer, move // it to the start of the buffer if (pos < bufPos + bufLen) { bufLen -= pos - bufPos; memmove(buf, buf + (pos - bufPos), bufLen); bufPos = pos; // otherwise discard data from the // stream until we get to the requested position } else { bufPos += bufLen; bufLen = 0; while (bufPos < pos) { if ((c = (*getChar)(data)) < 0) { return gFalse; } ++bufPos; } } } // read the rest of the requested data while (bufPos + bufLen < pos + len) { if ((c = (*getChar)(data)) < 0) { return gFalse; } buf[bufLen++] = (char)c; } return gTrue; } //------------------------------------------------------------------------ static FoFiIdentifierType identify(Reader *reader); static FoFiIdentifierType identifyOpenType(Reader *reader); static FoFiIdentifierType identifyCFF(Reader *reader, int start); FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) { MemReader *reader; FoFiIdentifierType type; if (!(reader = MemReader::make(file, len))) { return fofiIdError; } type = identify(reader); delete reader; return type; } FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) { FileReader *reader; FoFiIdentifierType type; if (!(reader = FileReader::make(fileName))) { return fofiIdError; } type = identify(reader); delete reader; return type; } FoFiIdentifierType FoFiIdentifier::identifyStream(int (*getChar)(void *data), void *data) { StreamReader *reader; FoFiIdentifierType type; if (!(reader = StreamReader::make(getChar, data))) { return fofiIdError; } type = identify(reader); delete reader; return type; } static FoFiIdentifierType identify(Reader *reader) { Guint n; //----- PFA if (reader->cmp(0, "%!PS-AdobeFont-1") || reader->cmp(0, "%!FontType1")) { return fofiIdType1PFA; } //----- PFB if (reader->getByte(0) == 0x80 && reader->getByte(1) == 0x01 && reader->getU32LE(2, &n)) { if ((n >= 16 && reader->cmp(6, "%!PS-AdobeFont-1")) || (n >= 11 && reader->cmp(6, "%!FontType1"))) { return fofiIdType1PFB; } } //----- TrueType if ((reader->getByte(0) == 0x00 && reader->getByte(1) == 0x01 && reader->getByte(2) == 0x00 && reader->getByte(3) == 0x00) || (reader->getByte(0) == 0x74 && // 'true' reader->getByte(1) == 0x72 && reader->getByte(2) == 0x75 && reader->getByte(3) == 0x65)) { return fofiIdTrueType; } if (reader->getByte(0) == 0x74 && // 'ttcf' reader->getByte(1) == 0x74 && reader->getByte(2) == 0x63 && reader->getByte(3) == 0x66) { return fofiIdTrueTypeCollection; } //----- OpenType if (reader->getByte(0) == 0x4f && // 'OTTO reader->getByte(1) == 0x54 && reader->getByte(2) == 0x54 && reader->getByte(3) == 0x4f) { return identifyOpenType(reader); } //----- CFF if (reader->getByte(0) == 0x01 && reader->getByte(1) == 0x00) { return identifyCFF(reader, 0); } // some tools embed CFF fonts with an extra whitespace char at the // beginning if (reader->getByte(1) == 0x01 && reader->getByte(2) == 0x00) { return identifyCFF(reader, 1); } return fofiIdUnknown; } static FoFiIdentifierType identifyOpenType(Reader *reader) { FoFiIdentifierType type; Guint offset; int nTables, i; if (!reader->getU16BE(4, &nTables)) { return fofiIdUnknown; } for (i = 0; i < nTables; ++i) { if (reader->cmp(12 + i*16, "CFF ")) { if (reader->getU32BE(12 + i*16 + 8, &offset) && offset < (Guint)INT_MAX) { type = identifyCFF(reader, (int)offset); if (type == fofiIdCFF8Bit) { type = fofiIdOpenTypeCFF8Bit; } else if (type == fofiIdCFFCID) { type = fofiIdOpenTypeCFFCID; } return type; } return fofiIdUnknown; } } return fofiIdUnknown; } static FoFiIdentifierType identifyCFF(Reader *reader, int start) { Guint offset0, offset1; int hdrSize, offSize0, offSize1, pos, endPos, b0, n, i; //----- read the header if (reader->getByte(start) != 0x01 || reader->getByte(start + 1) != 0x00) { return fofiIdUnknown; } if ((hdrSize = reader->getByte(start + 2)) < 0) { return fofiIdUnknown; } if ((offSize0 = reader->getByte(start + 3)) < 1 || offSize0 > 4) { return fofiIdUnknown; } pos = start + hdrSize; if (pos < 0) { return fofiIdUnknown; } //----- skip the name index if (!reader->getU16BE(pos, &n)) { return fofiIdUnknown; } if (n == 0) { pos += 2; } else { if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { return fofiIdUnknown; } if (!reader->getUVarBE(pos + 3 + n * offSize1, offSize1, &offset1) || offset1 > (Guint)INT_MAX) { return fofiIdUnknown; } pos += 3 + (n + 1) * offSize1 + (int)offset1 - 1; } if (pos < 0) { return fofiIdUnknown; } //----- parse the top dict index if (!reader->getU16BE(pos, &n) || n < 1) { return fofiIdUnknown; } if ((offSize1 = reader->getByte(pos + 2)) < 1 || offSize1 > 4) { return fofiIdUnknown; } if (!reader->getUVarBE(pos + 3, offSize1, &offset0) || offset0 > (Guint)INT_MAX || !reader->getUVarBE(pos + 3 + offSize1, offSize1, &offset1) || offset1 > (Guint)INT_MAX || offset0 > offset1) { return fofiIdUnknown; } pos = pos + 3 + (n + 1) * offSize1 + (int)offset0 - 1; endPos = pos + 3 + (n + 1) * offSize1 + (int)offset1 - 1; if (pos < 0 || endPos < 0 || pos > endPos) { return fofiIdUnknown; } //----- parse the top dict, look for ROS as first entry // for a CID font, the top dict starts with: // ROS for (i = 0; i < 3; ++i) { b0 = reader->getByte(pos++); if (b0 == 0x1c) { pos += 2; } else if (b0 == 0x1d) { pos += 4; } else if (b0 >= 0xf7 && b0 <= 0xfe) { pos += 1; } else if (b0 < 0x20 || b0 > 0xf6) { return fofiIdCFF8Bit; } if (pos >= endPos || pos < 0) { return fofiIdCFF8Bit; } } if (pos + 1 < endPos && reader->getByte(pos) == 12 && reader->getByte(pos + 1) == 30) { return fofiIdCFFCID; } else { return fofiIdCFF8Bit; } } xpdf-3.03/fofi/FoFiEncodings.h0000644000076400007640000000175511622305345015474 0ustar dereknderekn//======================================================================== // // FoFiEncodings.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FOFIENCODINGS_H #define FOFIENCODINGS_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" //------------------------------------------------------------------------ // Type 1 and 1C font data //------------------------------------------------------------------------ extern const char *fofiType1StandardEncoding[256]; extern const char *fofiType1ExpertEncoding[256]; //------------------------------------------------------------------------ // Type 1C font data //------------------------------------------------------------------------ extern const char *fofiType1CStdStrings[391]; extern Gushort fofiType1CISOAdobeCharset[229]; extern Gushort fofiType1CExpertCharset[166]; extern Gushort fofiType1CExpertSubsetCharset[87]; #endif xpdf-3.03/fofi/FoFiTrueType.h0000644000076400007640000001515611622305345015344 0ustar dereknderekn//======================================================================== // // FoFiTrueType.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FOFITRUETYPE_H #define FOFITRUETYPE_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "FoFiBase.h" class GString; class GHash; struct TrueTypeTable; struct TrueTypeCmap; //------------------------------------------------------------------------ // FoFiTrueType //------------------------------------------------------------------------ class FoFiTrueType: public FoFiBase { public: // Create a FoFiTrueType object from a memory buffer. static FoFiTrueType *make(char *fileA, int lenA); // Create a FoFiTrueType object from a file on disk. static FoFiTrueType *load(char *fileName); virtual ~FoFiTrueType(); // Returns true if this an OpenType font containing CFF data, false // if it's a TrueType font (or OpenType font with TrueType data). GBool isOpenTypeCFF() { return openTypeCFF; } // Return the number of cmaps defined by this font. int getNumCmaps(); // Return the platform ID of the th cmap. int getCmapPlatform(int i); // Return the encoding ID of the th cmap. int getCmapEncoding(int i); // Return the index of the cmap for , . Returns // -1 if there is no corresponding cmap. int findCmap(int platform, int encoding); // Return the GID corresponding to according to the th cmap. int mapCodeToGID(int i, int c); // Returns the GID corresponding to according to the post // table. Returns 0 if there is no mapping for or if the // font does not have a post table. int mapNameToGID(char *name); // Return the mapping from CIDs to GIDs, and return the number of // CIDs in *. This is only useful for CID fonts. (Only // useful for OpenType CFF fonts.) int *getCIDToGIDMap(int *nCIDs); // Returns the least restrictive embedding licensing right (as // defined by the TrueType spec): // * 4: OS/2 table is missing or invalid // * 3: installable embedding // * 2: editable embedding // * 1: preview & print embedding // * 0: restricted license embedding int getEmbeddingRights(); // Return the font matrix as an array of six numbers. (Only useful // for OpenType CFF fonts.) void getFontMatrix(double *mat); // Convert to a Type 42 font, suitable for embedding in a PostScript // file. will be used as the PostScript font name (so we // don't need to depend on the 'name' table in the font). The // array specifies the mapping from char codes to names. // If is NULL, the encoding is unknown or undefined. The // array specifies the mapping from char codes to GIDs. // (Not useful for OpenType CFF fonts.) void convertToType42(char *psName, char **encoding, int *codeToGID, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 1 font, suitable for embedding in a PostScript // file. This is only useful with 8-bit fonts. If is // not NULL, it will be used in place of the encoding in the Type 1C // font. If is true the eexec section will be hex-encoded, // otherwise it will be left as binary data. If is // non-NULL, it will be used as the PostScript font name. (Only // useful for OpenType CFF fonts.) void convertToType1(char *psName, const char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 2 CIDFont, suitable for embedding in a // PostScript file. will be used as the PostScript font // name (so we don't need to depend on the 'name' table in the // font). The array maps CIDs to GIDs; it has // entries. (Not useful for OpenType CFF fonts.) void convertToCIDType2(char *psName, int *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 CIDFont, suitable for embedding in a // PostScript file. will be used as the PostScript font // name. (Only useful for OpenType CFF fonts.) void convertToCIDType0(char *psName, int *cidMap, int nCIDs, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 (but non-CID) composite font, suitable for // embedding in a PostScript file. will be used as the // PostScript font name (so we don't need to depend on the 'name' // table in the font). The array maps CIDs to GIDs; it has // entries. (Not useful for OpenType CFF fonts.) void convertToType0(char *psName, int *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 (but non-CID) composite font, suitable for // embedding in a PostScript file. will be used as the // PostScript font name. (Only useful for OpenType CFF fonts.) void convertToType0(char *psName, int *cidMap, int nCIDs, FoFiOutputFunc outputFunc, void *outputStream); // Write a clean TTF file, filling in missing tables and correcting // various other errors. If is non-NULL, the font is renamed // to . If is non-NULL, the font is re-encoded, // using a Windows Unicode cmap. If is NULL and the font is // complete and correct, it will be written unmodified. (Not useful // for OpenType CFF fonts.) void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, char *name = NULL, int *codeToGID = NULL); // Returns a pointer to the CFF font embedded in this OpenType font. // If successful, sets * and *, and returns true. // Otherwise returns false. (Only useful for OpenType CFF fonts). GBool getCFFBlock(char **start, int *length); private: FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA); void cvtEncoding(char **encoding, FoFiOutputFunc outputFunc, void *outputStream); void cvtCharStrings(char **encoding, int *codeToGID, FoFiOutputFunc outputFunc, void *outputStream); void cvtSfnts(FoFiOutputFunc outputFunc, void *outputStream, GString *name, GBool needVerticalMetrics, int *maxUsedGlyph); void dumpString(Guchar *s, int length, FoFiOutputFunc outputFunc, void *outputStream); Guint computeTableChecksum(Guchar *data, int length); void parse(); void readPostTable(); int seekTable(const char *tag); TrueTypeTable *tables; int nTables; TrueTypeCmap *cmaps; int nCmaps; int nGlyphs; int locaFmt; int bbox[4]; GHash *nameToGID; GBool openTypeCFF; GBool parsedOk; }; #endif xpdf-3.03/fofi/FoFiEncodings.cc0000644000076400007640000003476111622305345015635 0ustar dereknderekn//======================================================================== // // FoFiEncodings.cc // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include "FoFiEncodings.h" //------------------------------------------------------------------------ // Type 1 and 1C font data //------------------------------------------------------------------------ const char *fofiType1StandardEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", NULL, "endash", "dagger", "daggerdbl", "periodcentered", NULL, "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", NULL, "questiondown", NULL, "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", NULL, "ring", "cedilla", NULL, "hungarumlaut", "ogonek", "caron", "emdash", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "AE", NULL, "ordfeminine", NULL, NULL, NULL, NULL, "Lslash", "Oslash", "OE", "ordmasculine", NULL, NULL, NULL, NULL, NULL, "ae", NULL, NULL, NULL, "dotlessi", NULL, NULL, "lslash", "oslash", "oe", "germandbls", NULL, NULL, NULL, NULL }; const char *fofiType1ExpertEncoding[256] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "space", "exclamsmall", "Hungarumlautsmall", NULL, "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "comma", "hyphen", "period", "fraction", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "colon", "semicolon", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", NULL, "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", NULL, NULL, NULL, "isuperior", NULL, NULL, "lsuperior", "msuperior", "nsuperior", "osuperior", NULL, NULL, "rsuperior", "ssuperior", "tsuperior", NULL, "ff", "fi", "fl", "ffi", "ffl", "parenleftinferior", NULL, "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "exclamdownsmall", "centoldstyle", "Lslashsmall", NULL, NULL, "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", NULL, "Dotaccentsmall", NULL, NULL, "Macronsmall", NULL, NULL, "figuredash", "hypheninferior", NULL, NULL, "Ogoneksmall", "Ringsmall", "Cedillasmall", NULL, NULL, NULL, "onequarter", "onehalf", "threequarters", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", NULL, NULL, "zerosuperior", "onesuperior", "twosuperior", "threesuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall" }; //------------------------------------------------------------------------ // Type 1C font data //------------------------------------------------------------------------ const char *fofiType1CStdStrings[391] = { ".notdef", "space", "exclam", "quotedbl", "numbersign", "dollar", "percent", "ampersand", "quoteright", "parenleft", "parenright", "asterisk", "plus", "comma", "hyphen", "period", "slash", "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "colon", "semicolon", "less", "equal", "greater", "question", "at", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "bracketleft", "backslash", "bracketright", "asciicircum", "underscore", "quoteleft", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "braceleft", "bar", "braceright", "asciitilde", "exclamdown", "cent", "sterling", "fraction", "yen", "florin", "section", "currency", "quotesingle", "quotedblleft", "guillemotleft", "guilsinglleft", "guilsinglright", "fi", "fl", "endash", "dagger", "daggerdbl", "periodcentered", "paragraph", "bullet", "quotesinglbase", "quotedblbase", "quotedblright", "guillemotright", "ellipsis", "perthousand", "questiondown", "grave", "acute", "circumflex", "tilde", "macron", "breve", "dotaccent", "dieresis", "ring", "cedilla", "hungarumlaut", "ogonek", "caron", "emdash", "AE", "ordfeminine", "Lslash", "Oslash", "OE", "ordmasculine", "ae", "dotlessi", "lslash", "oslash", "oe", "germandbls", "onesuperior", "logicalnot", "mu", "trademark", "Eth", "onehalf", "plusminus", "Thorn", "onequarter", "divide", "brokenbar", "degree", "thorn", "threequarters", "twosuperior", "registered", "minus", "eth", "multiply", "threesuperior", "copyright", "Aacute", "Acircumflex", "Adieresis", "Agrave", "Aring", "Atilde", "Ccedilla", "Eacute", "Ecircumflex", "Edieresis", "Egrave", "Iacute", "Icircumflex", "Idieresis", "Igrave", "Ntilde", "Oacute", "Ocircumflex", "Odieresis", "Ograve", "Otilde", "Scaron", "Uacute", "Ucircumflex", "Udieresis", "Ugrave", "Yacute", "Ydieresis", "Zcaron", "aacute", "acircumflex", "adieresis", "agrave", "aring", "atilde", "ccedilla", "eacute", "ecircumflex", "edieresis", "egrave", "iacute", "icircumflex", "idieresis", "igrave", "ntilde", "oacute", "ocircumflex", "odieresis", "ograve", "otilde", "scaron", "uacute", "ucircumflex", "udieresis", "ugrave", "yacute", "ydieresis", "zcaron", "exclamsmall", "Hungarumlautsmall", "dollaroldstyle", "dollarsuperior", "ampersandsmall", "Acutesmall", "parenleftsuperior", "parenrightsuperior", "twodotenleader", "onedotenleader", "zerooldstyle", "oneoldstyle", "twooldstyle", "threeoldstyle", "fouroldstyle", "fiveoldstyle", "sixoldstyle", "sevenoldstyle", "eightoldstyle", "nineoldstyle", "commasuperior", "threequartersemdash", "periodsuperior", "questionsmall", "asuperior", "bsuperior", "centsuperior", "dsuperior", "esuperior", "isuperior", "lsuperior", "msuperior", "nsuperior", "osuperior", "rsuperior", "ssuperior", "tsuperior", "ff", "ffi", "ffl", "parenleftinferior", "parenrightinferior", "Circumflexsmall", "hyphensuperior", "Gravesmall", "Asmall", "Bsmall", "Csmall", "Dsmall", "Esmall", "Fsmall", "Gsmall", "Hsmall", "Ismall", "Jsmall", "Ksmall", "Lsmall", "Msmall", "Nsmall", "Osmall", "Psmall", "Qsmall", "Rsmall", "Ssmall", "Tsmall", "Usmall", "Vsmall", "Wsmall", "Xsmall", "Ysmall", "Zsmall", "colonmonetary", "onefitted", "rupiah", "Tildesmall", "exclamdownsmall", "centoldstyle", "Lslashsmall", "Scaronsmall", "Zcaronsmall", "Dieresissmall", "Brevesmall", "Caronsmall", "Dotaccentsmall", "Macronsmall", "figuredash", "hypheninferior", "Ogoneksmall", "Ringsmall", "Cedillasmall", "questiondownsmall", "oneeighth", "threeeighths", "fiveeighths", "seveneighths", "onethird", "twothirds", "zerosuperior", "foursuperior", "fivesuperior", "sixsuperior", "sevensuperior", "eightsuperior", "ninesuperior", "zeroinferior", "oneinferior", "twoinferior", "threeinferior", "fourinferior", "fiveinferior", "sixinferior", "seveninferior", "eightinferior", "nineinferior", "centinferior", "dollarinferior", "periodinferior", "commainferior", "Agravesmall", "Aacutesmall", "Acircumflexsmall", "Atildesmall", "Adieresissmall", "Aringsmall", "AEsmall", "Ccedillasmall", "Egravesmall", "Eacutesmall", "Ecircumflexsmall", "Edieresissmall", "Igravesmall", "Iacutesmall", "Icircumflexsmall", "Idieresissmall", "Ethsmall", "Ntildesmall", "Ogravesmall", "Oacutesmall", "Ocircumflexsmall", "Otildesmall", "Odieresissmall", "OEsmall", "Oslashsmall", "Ugravesmall", "Uacutesmall", "Ucircumflexsmall", "Udieresissmall", "Yacutesmall", "Thornsmall", "Ydieresissmall", "001.000", "001.001", "001.002", "001.003", "Black", "Bold", "Book", "Light", "Medium", "Regular", "Roman", "Semibold" }; Gushort fofiType1CISOAdobeCharset[229] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228 }; Gushort fofiType1CExpertCharset[166] = { 0, 1, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 158, 155, 163, 319, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372, 373, 374, 375, 376, 377, 378 }; Gushort fofiType1CExpertSubsetCharset[87] = { 0, 1, 231, 232, 235, 236, 237, 238, 13, 14, 15, 99, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 27, 28, 249, 250, 251, 253, 254, 255, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 109, 110, 267, 268, 269, 270, 272, 300, 301, 302, 305, 314, 315, 158, 155, 163, 320, 321, 322, 323, 324, 325, 326, 150, 164, 169, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346 }; xpdf-3.03/fofi/FoFiBase.cc0000644000076400007640000000623511622305345014571 0ustar dereknderekn//======================================================================== // // FoFiBase.cc // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "FoFiBase.h" //------------------------------------------------------------------------ // FoFiBase //------------------------------------------------------------------------ FoFiBase::FoFiBase(char *fileA, int lenA, GBool freeFileDataA) { fileData = file = (Guchar *)fileA; len = lenA; freeFileData = freeFileDataA; } FoFiBase::~FoFiBase() { if (freeFileData) { gfree(fileData); } } char *FoFiBase::readFile(char *fileName, int *fileLen) { FILE *f; char *buf; int n; if (!(f = fopen(fileName, "rb"))) { return NULL; } fseek(f, 0, SEEK_END); n = (int)ftell(f); if (n < 0) { fclose(f); return NULL; } fseek(f, 0, SEEK_SET); buf = (char *)gmalloc(n); if ((int)fread(buf, 1, n, f) != n) { gfree(buf); fclose(f); return NULL; } fclose(f); *fileLen = n; return buf; } int FoFiBase::getS8(int pos, GBool *ok) { int x; if (pos < 0 || pos >= len) { *ok = gFalse; return 0; } x = file[pos]; if (x & 0x80) { x |= ~0xff; } return x; } int FoFiBase::getU8(int pos, GBool *ok) { if (pos < 0 || pos >= len) { *ok = gFalse; return 0; } return file[pos]; } int FoFiBase::getS16BE(int pos, GBool *ok) { int x; if (pos < 0 || pos+1 >= len || pos > INT_MAX - 1) { *ok = gFalse; return 0; } x = file[pos]; x = (x << 8) + file[pos+1]; if (x & 0x8000) { x |= ~0xffff; } return x; } int FoFiBase::getU16BE(int pos, GBool *ok) { int x; if (pos < 0 || pos+1 >= len || pos > INT_MAX - 1) { *ok = gFalse; return 0; } x = file[pos]; x = (x << 8) + file[pos+1]; return x; } int FoFiBase::getS32BE(int pos, GBool *ok) { int x; if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) { *ok = gFalse; return 0; } x = file[pos]; x = (x << 8) + file[pos+1]; x = (x << 8) + file[pos+2]; x = (x << 8) + file[pos+3]; if (x & 0x80000000) { x |= ~0xffffffff; } return x; } Guint FoFiBase::getU32BE(int pos, GBool *ok) { Guint x; if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) { *ok = gFalse; return 0; } x = file[pos]; x = (x << 8) + file[pos+1]; x = (x << 8) + file[pos+2]; x = (x << 8) + file[pos+3]; return x; } Guint FoFiBase::getU32LE(int pos, GBool *ok) { Guint x; if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) { *ok = gFalse; return 0; } x = file[pos+3]; x = (x << 8) + file[pos+2]; x = (x << 8) + file[pos+1]; x = (x << 8) + file[pos]; return x; } Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) { Guint x; int i; if (pos < 0 || pos + size > len || pos > INT_MAX - size) { *ok = gFalse; return 0; } x = 0; for (i = 0; i < size; ++i) { x = (x << 8) + file[pos + i]; } return x; } GBool FoFiBase::checkRegion(int pos, int size) { return pos >= 0 && pos + size >= pos && pos + size <= len; } xpdf-3.03/fofi/FoFiType1C.cc0000644000076400007640000023455411622305345015033 0ustar dereknderekn//======================================================================== // // FoFiType1C.cc // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include "gmem.h" #include "GString.h" #include "FoFiEncodings.h" #include "FoFiType1C.h" //------------------------------------------------------------------------ static char hexChars[17] = "0123456789ABCDEF"; //------------------------------------------------------------------------ // FoFiType1C //------------------------------------------------------------------------ FoFiType1C *FoFiType1C::make(char *fileA, int lenA) { FoFiType1C *ff; ff = new FoFiType1C(fileA, lenA, gFalse); if (!ff->parse()) { delete ff; return NULL; } return ff; } FoFiType1C *FoFiType1C::load(char *fileName) { FoFiType1C *ff; char *fileA; int lenA; if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { return NULL; } ff = new FoFiType1C(fileA, lenA, gTrue); if (!ff->parse()) { delete ff; return NULL; } return ff; } FoFiType1C::FoFiType1C(char *fileA, int lenA, GBool freeFileDataA): FoFiBase(fileA, lenA, freeFileDataA) { name = NULL; encoding = NULL; privateDicts = NULL; fdSelect = NULL; charset = NULL; } FoFiType1C::~FoFiType1C() { int i; if (name) { delete name; } if (encoding && encoding != (char **)fofiType1StandardEncoding && encoding != (char **)fofiType1ExpertEncoding) { for (i = 0; i < 256; ++i) { gfree(encoding[i]); } gfree(encoding); } if (privateDicts) { gfree(privateDicts); } if (fdSelect) { gfree(fdSelect); } if (charset && charset != fofiType1CISOAdobeCharset && charset != fofiType1CExpertCharset && charset != fofiType1CExpertSubsetCharset) { gfree(charset); } } char *FoFiType1C::getName() { return name ? name->getCString() : (char *)NULL; } char **FoFiType1C::getEncoding() { return encoding; } GString *FoFiType1C::getGlyphName(int gid) { char buf[256]; GBool ok; ok = gTrue; getString(charset[gid], buf, &ok); if (!ok) { return NULL; } return new GString(buf); } int *FoFiType1C::getCIDToGIDMap(int *nCIDs) { int *map; int n, i; // a CID font's top dict has ROS as the first operator if (topDict.firstOp != 0x0c1e) { *nCIDs = 0; return NULL; } // in a CID font, the charset data is the GID-to-CID mapping, so all // we have to do is reverse it n = 0; for (i = 0; i < nGlyphs; ++i) { if (charset[i] > n) { n = charset[i]; } } ++n; map = (int *)gmallocn(n, sizeof(int)); memset(map, 0, n * sizeof(int)); for (i = 0; i < nGlyphs; ++i) { map[charset[i]] = i; } *nCIDs = n; return map; } void FoFiType1C::getFontMatrix(double *mat) { int i; if (topDict.firstOp == 0x0c1e && privateDicts[0].hasFontMatrix) { if (topDict.hasFontMatrix) { mat[0] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[2]; mat[1] = topDict.fontMatrix[0] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[1] * privateDicts[0].fontMatrix[3]; mat[2] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[2]; mat[3] = topDict.fontMatrix[2] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[3] * privateDicts[0].fontMatrix[3]; mat[4] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[0] + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[2]; mat[5] = topDict.fontMatrix[4] * privateDicts[0].fontMatrix[1] + topDict.fontMatrix[5] * privateDicts[0].fontMatrix[3]; } else { for (i = 0; i < 6; ++i) { mat[i] = privateDicts[0].fontMatrix[i]; } } } else { for (i = 0; i < 6; ++i) { mat[i] = topDict.fontMatrix[i]; } } } void FoFiType1C::convertToType1(char *psName, const char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream) { int psNameLen; Type1CEexecBuf eb; Type1CIndex subrIdx; Type1CIndexVal val; GString *buf; char buf2[256]; const char **enc; GBool ok; int i; if (psName) { psNameLen = (int)strlen(psName); } else { psName = name->getCString(); psNameLen = name->getLength(); } // write header and font dictionary, up to encoding ok = gTrue; (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); (*outputFunc)(outputStream, psName, psNameLen); if (topDict.versionSID != 0) { getString(topDict.versionSID, buf2, &ok); (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); } (*outputFunc)(outputStream, "\n", 1); // the dictionary needs room for 12 entries: the following 9, plus // Private and CharStrings (in the eexec section) and FID (which is // added by definefont) (*outputFunc)(outputStream, "12 dict begin\n", 14); (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); if (topDict.versionSID != 0) { (*outputFunc)(outputStream, "/version ", 9); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.noticeSID != 0) { getString(topDict.noticeSID, buf2, &ok); (*outputFunc)(outputStream, "/Notice ", 8); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.copyrightSID != 0) { getString(topDict.copyrightSID, buf2, &ok); (*outputFunc)(outputStream, "/Copyright ", 11); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.fullNameSID != 0) { getString(topDict.fullNameSID, buf2, &ok); (*outputFunc)(outputStream, "/FullName ", 10); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.familyNameSID != 0) { getString(topDict.familyNameSID, buf2, &ok); (*outputFunc)(outputStream, "/FamilyName ", 12); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.weightSID != 0) { getString(topDict.weightSID, buf2, &ok); (*outputFunc)(outputStream, "/Weight ", 8); writePSString(buf2, outputFunc, outputStream); (*outputFunc)(outputStream, " readonly def\n", 14); } if (topDict.isFixedPitch) { (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); } else { (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); } buf = GString::format("/ItalicAngle {0:.4g} def\n", topDict.italicAngle); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/UnderlinePosition {0:.4g} def\n", topDict.underlinePosition); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/UnderlineThickness {0:.4g} def\n", topDict.underlineThickness); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "end readonly def\n", 17); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, psNameLen); (*outputFunc)(outputStream, " def\n", 5); buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FontType 1 def\n", 16); buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] readonly def\n", topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] readonly def\n", topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; if (topDict.uniqueID != 0) { buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } // write the encoding (*outputFunc)(outputStream, "/Encoding ", 10); if (!newEncoding && encoding == (char **)fofiType1StandardEncoding) { (*outputFunc)(outputStream, "StandardEncoding def\n", 21); } else { (*outputFunc)(outputStream, "256 array\n", 10); (*outputFunc)(outputStream, "0 1 255 {1 index exch /.notdef put} for\n", 40); enc = newEncoding ? newEncoding : (const char **)encoding; for (i = 0; i < 256; ++i) { if (enc[i]) { buf = GString::format("dup {0:d} /{1:s} put\n", i, enc[i]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } } (*outputFunc)(outputStream, "readonly def\n", 13); } (*outputFunc)(outputStream, "currentdict end\n", 16); // start the binary section (*outputFunc)(outputStream, "currentfile eexec\n", 18); eb.outputFunc = outputFunc; eb.outputStream = outputStream; eb.ascii = ascii; eb.r1 = 55665; eb.line = 0; // write the private dictionary eexecWrite(&eb, "\x83\xca\x73\xd5"); eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" " executeonly def\n"); eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); eexecWrite(&eb, "/MinFeature {16 16} def\n"); eexecWrite(&eb, "/password 5839 def\n"); if (privateDicts[0].nBlueValues) { eexecWrite(&eb, "/BlueValues ["); for (i = 0; i < privateDicts[0].nBlueValues; ++i) { buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", privateDicts[0].blueValues[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].nOtherBlues) { eexecWrite(&eb, "/OtherBlues ["); for (i = 0; i < privateDicts[0].nOtherBlues; ++i) { buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", privateDicts[0].otherBlues[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].nFamilyBlues) { eexecWrite(&eb, "/FamilyBlues ["); for (i = 0; i < privateDicts[0].nFamilyBlues; ++i) { buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", privateDicts[0].familyBlues[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].nFamilyOtherBlues) { eexecWrite(&eb, "/FamilyOtherBlues ["); for (i = 0; i < privateDicts[0].nFamilyOtherBlues; ++i) { buf = GString::format("{0:s}{1:d}", i > 0 ? " " : "", privateDicts[0].familyOtherBlues[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].blueScale != 0.039625) { buf = GString::format("/BlueScale {0:.4g} def\n", privateDicts[0].blueScale); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].blueShift != 7) { buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].blueFuzz != 1) { buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].hasStdHW) { buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].hasStdVW) { buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[0].stdVW); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].nStemSnapH) { eexecWrite(&eb, "/StemSnapH ["); for (i = 0; i < privateDicts[0].nStemSnapH; ++i) { buf = GString::format("{0:s}{1:.4g}", i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].nStemSnapV) { eexecWrite(&eb, "/StemSnapV ["); for (i = 0; i < privateDicts[0].nStemSnapV; ++i) { buf = GString::format("{0:s}{1:.4g}", i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[0].hasForceBold) { buf = GString::format("/ForceBold {0:s} def\n", privateDicts[0].forceBold ? "true" : "false"); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].forceBoldThreshold != 0) { buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", privateDicts[0].forceBoldThreshold); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].languageGroup != 0) { buf = GString::format("/LanguageGroup {0:d} def\n", privateDicts[0].languageGroup); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[0].expansionFactor != 0.06) { buf = GString::format("/ExpansionFactor {0:.4g} def\n", privateDicts[0].expansionFactor); eexecWrite(&eb, buf->getCString()); delete buf; } // set up subroutines ok = gTrue; getIndex(privateDicts[0].subrsOffset, &subrIdx, &ok); if (!ok) { subrIdx.pos = -1; } // write the CharStrings buf = GString::format("2 index /CharStrings {0:d} dict dup begin\n", nGlyphs); eexecWrite(&eb, buf->getCString()); delete buf; for (i = 0; i < nGlyphs; ++i) { ok = gTrue; getIndexVal(&charStringsIdx, i, &val, &ok); if (ok) { getString(charset[i], buf2, &ok); if (ok) { eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); } } } eexecWrite(&eb, "end\n"); eexecWrite(&eb, "end\n"); eexecWrite(&eb, "readonly put\n"); eexecWrite(&eb, "noaccess put\n"); eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); eexecWrite(&eb, "mark currentfile closefile\n"); // trailer if (ascii && eb.line > 0) { (*outputFunc)(outputStream, "\n", 1); } for (i = 0; i < 8; ++i) { (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); } (*outputFunc)(outputStream, "cleartomark\n", 12); } void FoFiType1C::convertToCIDType0(char *psName, int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream) { int *cidMap; GString *charStrings; int *charStringOffsets; Type1CIndex subrIdx; Type1CIndexVal val; int nCIDs, gdBytes; GString *buf; char buf2[256]; GBool ok; int gid, offset, n, i, j, k; // compute the CID count and build the CID-to-GID mapping if (codeMap) { nCIDs = nCodes; cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCodes; ++i) { if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { cidMap[i] = codeMap[i]; } else { cidMap[i] = -1; } } } else if (topDict.firstOp == 0x0c1e) { nCIDs = 0; for (i = 0; i < nGlyphs; ++i) { if (charset[i] >= nCIDs) { nCIDs = charset[i] + 1; } } cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = -1; } for (i = 0; i < nGlyphs; ++i) { cidMap[charset[i]] = i; } } else { nCIDs = nGlyphs; cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = i; } } // build the charstrings charStrings = new GString(); charStringOffsets = (int *)gmallocn(nCIDs + 1, sizeof(int)); for (i = 0; i < nCIDs; ++i) { charStringOffsets[i] = charStrings->getLength(); if ((gid = cidMap[i]) >= 0) { ok = gTrue; getIndexVal(&charStringsIdx, gid, &val, &ok); if (ok) { getIndex(privateDicts[fdSelect ? fdSelect[gid] : 0].subrsOffset, &subrIdx, &ok); if (!ok) { subrIdx.pos = -1; } cvtGlyph(val.pos, val.len, charStrings, &subrIdx, &privateDicts[fdSelect ? fdSelect[gid] : 0], gTrue); } } } charStringOffsets[nCIDs] = charStrings->getLength(); // compute gdBytes = number of bytes needed for charstring offsets // (offset size needs to account for the charstring offset table, // with a worst case of five bytes per entry, plus the charstrings // themselves) i = (nCIDs + 1) * 5 + charStrings->getLength(); if (i < 0x100) { gdBytes = 1; } else if (i < 0x10000) { gdBytes = 2; } else if (i < 0x1000000) { gdBytes = 3; } else { gdBytes = 4; } // begin the font dictionary (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); (*outputFunc)(outputStream, "20 dict begin\n", 14); (*outputFunc)(outputStream, "/CIDFontName /", 14); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); if (topDict.registrySID > 0 && topDict.orderingSID > 0) { ok = gTrue; getString(topDict.registrySID, buf2, &ok); if (ok) { (*outputFunc)(outputStream, " /Registry (", 13); (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); (*outputFunc)(outputStream, ") def\n", 6); } ok = gTrue; getString(topDict.orderingSID, buf2, &ok); if (ok) { (*outputFunc)(outputStream, " /Ordering (", 13); (*outputFunc)(outputStream, buf2, (int)strlen(buf2)); (*outputFunc)(outputStream, ") def\n", 6); } } else { (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); } buf = GString::format(" /Supplement {0:d} def\n", topDict.supplement); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "end def\n", 8); if (topDict.hasFontMatrix) { buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } else if (privateDicts[0].hasFontMatrix) { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); } else { (*outputFunc)(outputStream, "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); } buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); (*outputFunc)(outputStream, " /FSType 8 def\n", 16); (*outputFunc)(outputStream, "end def\n", 8); // CIDFont-specific entries buf = GString::format("/CIDCount {0:d} def\n", nCIDs); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); buf = GString::format("/GDBytes {0:d} def\n", gdBytes); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); if (topDict.paintType != 0) { buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } // FDArray entry buf = GString::format("/FDArray {0:d} array\n", nFDs); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; for (i = 0; i < nFDs; ++i) { buf = GString::format("dup {0:d} 10 dict begin\n", i); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FontType 1 def\n", 16); if (privateDicts[i].hasFontMatrix) { buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", privateDicts[i].fontMatrix[0], privateDicts[i].fontMatrix[1], privateDicts[i].fontMatrix[2], privateDicts[i].fontMatrix[3], privateDicts[i].fontMatrix[4], privateDicts[i].fontMatrix[5]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } else { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); } buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); if (privateDicts[i].nBlueValues) { (*outputFunc)(outputStream, "/BlueValues [", 13); for (j = 0; j < privateDicts[i].nBlueValues; ++j) { buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", privateDicts[i].blueValues[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].nOtherBlues) { (*outputFunc)(outputStream, "/OtherBlues [", 13); for (j = 0; j < privateDicts[i].nOtherBlues; ++j) { buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", privateDicts[i].otherBlues[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].nFamilyBlues) { (*outputFunc)(outputStream, "/FamilyBlues [", 14); for (j = 0; j < privateDicts[i].nFamilyBlues; ++j) { buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", privateDicts[i].familyBlues[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].nFamilyOtherBlues) { (*outputFunc)(outputStream, "/FamilyOtherBlues [", 19); for (j = 0; j < privateDicts[i].nFamilyOtherBlues; ++j) { buf = GString::format("{0:s}{1:d}", j > 0 ? " " : "", privateDicts[i].familyOtherBlues[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].blueScale != 0.039625) { buf = GString::format("/BlueScale {0:.4g} def\n", privateDicts[i].blueScale); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].blueShift != 7) { buf = GString::format("/BlueShift {0:d} def\n", privateDicts[i].blueShift); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].blueFuzz != 1) { buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].hasStdHW) { buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].hasStdVW) { buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[i].stdVW); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].nStemSnapH) { (*outputFunc)(outputStream, "/StemSnapH [", 12); for (j = 0; j < privateDicts[i].nStemSnapH; ++j) { buf = GString::format("{0:s}{1:.4g}", j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].nStemSnapV) { (*outputFunc)(outputStream, "/StemSnapV [", 12); for (j = 0; j < privateDicts[i].nStemSnapV; ++j) { buf = GString::format("{0:s}{1:.4g}", j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); } if (privateDicts[i].hasForceBold) { buf = GString::format("/ForceBold {0:s} def\n", privateDicts[i].forceBold ? "true" : "false"); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].forceBoldThreshold != 0) { buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", privateDicts[i].forceBoldThreshold); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].languageGroup != 0) { buf = GString::format("/LanguageGroup {0:d} def\n", privateDicts[i].languageGroup); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (privateDicts[i].expansionFactor != 0.06) { buf = GString::format("/ExpansionFactor {0:.4g} def\n", privateDicts[i].expansionFactor); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "currentdict end def\n", 20); (*outputFunc)(outputStream, "currentdict end put\n", 20); } (*outputFunc)(outputStream, "def\n", 4); // start the binary section offset = (nCIDs + 1) * (1 + gdBytes); buf = GString::format("(Hex) {0:d} StartData\n", offset + charStrings->getLength()); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; // write the charstring offset (CIDMap) table for (i = 0; i <= nCIDs; i += 6) { for (j = 0; j < 6 && i+j <= nCIDs; ++j) { if (i+j < nCIDs && cidMap[i+j] >= 0 && fdSelect) { buf2[0] = (char)fdSelect[cidMap[i+j]]; } else { buf2[0] = (char)0; } n = offset + charStringOffsets[i+j]; for (k = gdBytes; k >= 1; --k) { buf2[k] = (char)(n & 0xff); n >>= 8; } for (k = 0; k <= gdBytes; ++k) { buf = GString::format("{0:02x}", buf2[k] & 0xff); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } } (*outputFunc)(outputStream, "\n", 1); } // write the charstring data n = charStrings->getLength(); for (i = 0; i < n; i += 32) { for (j = 0; j < 32 && i+j < n; ++j) { buf = GString::format("{0:02x}", charStrings->getChar(i+j) & 0xff); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (i + 32 >= n) { (*outputFunc)(outputStream, ">", 1); } (*outputFunc)(outputStream, "\n", 1); } gfree(charStringOffsets); delete charStrings; gfree(cidMap); } void FoFiType1C::convertToType0(char *psName, int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream) { int *cidMap; Type1CIndex subrIdx; Type1CIndexVal val; int nCIDs; GString *buf; Type1CEexecBuf eb; GBool ok; int fd, i, j, k; // compute the CID count and build the CID-to-GID mapping if (codeMap) { nCIDs = nCodes; cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCodes; ++i) { if (codeMap[i] >= 0 && codeMap[i] < nGlyphs) { cidMap[i] = codeMap[i]; } else { cidMap[i] = -1; } } } else if (topDict.firstOp == 0x0c1e) { nCIDs = 0; for (i = 0; i < nGlyphs; ++i) { if (charset[i] >= nCIDs) { nCIDs = charset[i] + 1; } } cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = -1; } for (i = 0; i < nGlyphs; ++i) { cidMap[charset[i]] = i; } } else { nCIDs = nGlyphs; cidMap = (int *)gmallocn(nCIDs, sizeof(int)); for (i = 0; i < nCIDs; ++i) { cidMap[i] = i; } } // write the descendant Type 1 fonts for (i = 0; i < nCIDs; i += 256) { //~ this assumes that all CIDs in this block have the same FD -- //~ to handle multiple FDs correctly, need to somehow divide the //~ font up by FD; as a kludge we ignore CID 0, which is .notdef fd = 0; // if fdSelect is NULL, we have an 8-bit font, so just leave fd=0 if (fdSelect) { for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { if (cidMap[i+j] >= 0) { fd = fdSelect[cidMap[i+j]]; break; } } } // font dictionary (unencrypted section) (*outputFunc)(outputStream, "16 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, (int)strlen(psName)); buf = GString::format("_{0:02x} def\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; (*outputFunc)(outputStream, "/FontType 1 def\n", 16); if (privateDicts[fd].hasFontMatrix) { buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", privateDicts[fd].fontMatrix[0], privateDicts[fd].fontMatrix[1], privateDicts[fd].fontMatrix[2], privateDicts[fd].fontMatrix[3], privateDicts[fd].fontMatrix[4], privateDicts[fd].fontMatrix[5]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } else if (topDict.hasFontMatrix) { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); } else { (*outputFunc)(outputStream, "/FontMatrix [0.001 0 0 0.001 0 0] def\n", 38); } buf = GString::format("/FontBBox [{0:.4g} {1:.4g} {2:.4g} {3:.4g}] def\n", topDict.fontBBox[0], topDict.fontBBox[1], topDict.fontBBox[2], topDict.fontBBox[3]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; buf = GString::format("/PaintType {0:d} def\n", topDict.paintType); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; if (topDict.paintType != 0) { buf = GString::format("/StrokeWidth {0:.4g} def\n", topDict.strokeWidth); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); for (j = 0; j < 256 && i+j < nCIDs; ++j) { buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } if (j < 256) { buf = GString::format("{0:d} 1 255 {{ 1 index exch /.notdef put }} for\n", j); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "readonly def\n", 13); (*outputFunc)(outputStream, "currentdict end\n", 16); // start the binary section (*outputFunc)(outputStream, "currentfile eexec\n", 18); eb.outputFunc = outputFunc; eb.outputStream = outputStream; eb.ascii = gTrue; eb.r1 = 55665; eb.line = 0; // start the private dictionary eexecWrite(&eb, "\x83\xca\x73\xd5"); eexecWrite(&eb, "dup /Private 32 dict dup begin\n"); eexecWrite(&eb, "/RD {string currentfile exch readstring pop}" " executeonly def\n"); eexecWrite(&eb, "/ND {noaccess def} executeonly def\n"); eexecWrite(&eb, "/NP {noaccess put} executeonly def\n"); eexecWrite(&eb, "/MinFeature {16 16} def\n"); eexecWrite(&eb, "/password 5839 def\n"); if (privateDicts[fd].nBlueValues) { eexecWrite(&eb, "/BlueValues ["); for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", privateDicts[fd].blueValues[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].nOtherBlues) { eexecWrite(&eb, "/OtherBlues ["); for (k = 0; k < privateDicts[fd].nOtherBlues; ++k) { buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", privateDicts[fd].otherBlues[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].nFamilyBlues) { eexecWrite(&eb, "/FamilyBlues ["); for (k = 0; k < privateDicts[fd].nFamilyBlues; ++k) { buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", privateDicts[fd].familyBlues[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].nFamilyOtherBlues) { eexecWrite(&eb, "/FamilyOtherBlues ["); for (k = 0; k < privateDicts[fd].nFamilyOtherBlues; ++k) { buf = GString::format("{0:s}{1:d}", k > 0 ? " " : "", privateDicts[fd].familyOtherBlues[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].blueScale != 0.039625) { buf = GString::format("/BlueScale {0:.4g} def\n", privateDicts[fd].blueScale); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].blueShift != 7) { buf = GString::format("/BlueShift {0:d} def\n", privateDicts[fd].blueShift); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].blueFuzz != 1) { buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[fd].blueFuzz); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].hasStdHW) { buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].hasStdVW) { buf = GString::format("/StdVW [{0:.4g}] def\n", privateDicts[fd].stdVW); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].nStemSnapH) { eexecWrite(&eb, "/StemSnapH ["); for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) { buf = GString::format("{0:s}{1:.4g}", k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].nStemSnapV) { eexecWrite(&eb, "/StemSnapV ["); for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) { buf = GString::format("{0:s}{1:.4g}", k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); eexecWrite(&eb, buf->getCString()); delete buf; } eexecWrite(&eb, "] def\n"); } if (privateDicts[fd].hasForceBold) { buf = GString::format("/ForceBold {0:s} def\n", privateDicts[fd].forceBold ? "true" : "false"); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].forceBoldThreshold != 0) { buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", privateDicts[fd].forceBoldThreshold); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].languageGroup != 0) { buf = GString::format("/LanguageGroup {0:d} def\n", privateDicts[fd].languageGroup); eexecWrite(&eb, buf->getCString()); delete buf; } if (privateDicts[fd].expansionFactor != 0.06) { buf = GString::format("/ExpansionFactor {0:.4g} def\n", privateDicts[fd].expansionFactor); eexecWrite(&eb, buf->getCString()); delete buf; } // set up the subroutines ok = gTrue; getIndex(privateDicts[fd].subrsOffset, &subrIdx, &ok); if (!ok) { subrIdx.pos = -1; } // start the CharStrings eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); // write the .notdef CharString ok = gTrue; getIndexVal(&charStringsIdx, 0, &val, &ok); if (ok) { eexecCvtGlyph(&eb, ".notdef", val.pos, val.len, &subrIdx, &privateDicts[fd]); } // write the CharStrings for (j = 0; j < 256 && i+j < nCIDs; ++j) { if (cidMap[i+j] >= 0) { ok = gTrue; getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); if (ok) { buf = GString::format("c{0:02x}", j); eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, &subrIdx, &privateDicts[fd]); delete buf; } } } eexecWrite(&eb, "end\n"); eexecWrite(&eb, "end\n"); eexecWrite(&eb, "readonly put\n"); eexecWrite(&eb, "noaccess put\n"); eexecWrite(&eb, "dup /FontName get exch definefont pop\n"); eexecWrite(&eb, "mark currentfile closefile\n"); // trailer if (eb.line > 0) { (*outputFunc)(outputStream, "\n", 1); } for (j = 0; j < 8; ++j) { (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); } (*outputFunc)(outputStream, "cleartomark\n", 12); } // write the Type 0 parent font (*outputFunc)(outputStream, "16 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, (int)strlen(psName)); (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 0 def\n", 16); if (topDict.hasFontMatrix) { buf = GString::format("/FontMatrix [{0:.8g} {1:.8g} {2:.8g} {3:.8g} {4:.8g} {5:.8g}] def\n", topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } else { (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); } (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); (*outputFunc)(outputStream, "/Encoding [\n", 12); for (i = 0; i < nCIDs; i += 256) { buf = GString::format("{0:d}\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); (*outputFunc)(outputStream, "/FDepVector [\n", 14); for (i = 0; i < nCIDs; i += 256) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, psName, (int)strlen(psName)); buf = GString::format("_{0:02x} findfont\n", i >> 8); (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); delete buf; } (*outputFunc)(outputStream, "] def\n", 6); (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); gfree(cidMap); } void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, int offset, int nBytes, Type1CIndex *subrIdx, Type1CPrivateDict *pDict) { GString *buf; GString *charBuf; // generate the charstring charBuf = new GString(); cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); buf = GString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength()); eexecWrite(eb, buf->getCString()); delete buf; eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(), charBuf->getLength()); eexecWrite(eb, " ND\n"); delete charBuf; } void FoFiType1C::cvtGlyph(int offset, int nBytes, GString *charBuf, Type1CIndex *subrIdx, Type1CPrivateDict *pDict, GBool top) { Type1CIndexVal val; GBool ok, dFP; double d, dx, dy; Gushort r2; Guchar byte; int pos, subrBias, start, i, k; start = charBuf->getLength(); if (top) { charBuf->append((char)73); charBuf->append((char)58); charBuf->append((char)147); charBuf->append((char)134); nOps = 0; nHints = 0; firstOp = gTrue; openPath = gFalse; } pos = offset; while (pos < offset + nBytes) { ok = gTrue; pos = getOp(pos, gTrue, &ok); if (!ok) { break; } if (!ops[nOps - 1].isNum) { --nOps; // drop the operator switch (ops[nOps].op) { case 0x0001: // hstem if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); } d = 0; dFP = gFalse; for (k = 0; k < nOps; k += 2) { // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints if (ops[k+1].num < 0) { d += ops[k].num + ops[k+1].num; dFP |= ops[k].isFP | ops[k+1].isFP; cvtNum(d, dFP, charBuf); cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); } else { d += ops[k].num; dFP |= ops[k].isFP; cvtNum(d, dFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); d += ops[k+1].num; dFP |= ops[k+1].isFP; } charBuf->append((char)1); } nHints += nOps / 2; nOps = 0; break; case 0x0003: // vstem if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); } d = 0; dFP = gFalse; for (k = 0; k < nOps; k += 2) { // convert Type 2 edge hints (-20 or -21) to Type 1 ghost hints if (ops[k+1].num < 0) { d += ops[k].num + ops[k+1].num; dFP |= ops[k].isFP | ops[k+1].isFP; cvtNum(d, dFP, charBuf); cvtNum(-ops[k+1].num, ops[k+1].isFP, charBuf); } else { d += ops[k].num; dFP |= ops[k].isFP; cvtNum(d, dFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); d += ops[k+1].num; dFP |= ops[k+1].isFP; } charBuf->append((char)3); } nHints += nOps / 2; nOps = 0; break; case 0x0004: // vmoveto if (firstOp) { cvtGlyphWidth(nOps == 2, charBuf, pDict); firstOp = gFalse; } if (openPath) { charBuf->append((char)9); openPath = gFalse; } if (nOps != 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); charBuf->append((char)4); nOps = 0; break; case 0x0005: // rlineto if (nOps < 2 || nOps % 2 != 0) { //~ error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); } for (k = 0; k < nOps; k += 2) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); charBuf->append((char)5); } nOps = 0; openPath = gTrue; break; case 0x0006: // hlineto if (nOps < 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); } for (k = 0; k < nOps; ++k) { cvtNum(ops[k].num, ops[k].isFP, charBuf); charBuf->append((char)((k & 1) ? 7 : 6)); } nOps = 0; openPath = gTrue; break; case 0x0007: // vlineto if (nOps < 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); } for (k = 0; k < nOps; ++k) { cvtNum(ops[k].num, ops[k].isFP, charBuf); charBuf->append((char)((k & 1) ? 6 : 7)); } nOps = 0; openPath = gTrue; break; case 0x0008: // rrcurveto if (nOps < 6 || nOps % 6 != 0) { //~ error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); } for (k = 0; k < nOps; k += 6) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); charBuf->append((char)8); } nOps = 0; openPath = gTrue; break; case 0x000a: // callsubr if (nOps >= 1) { subrBias = (subrIdx->len < 1240) ? 107 : (subrIdx->len < 33900) ? 1131 : 32768; k = subrBias + (int)ops[nOps - 1].num; --nOps; ok = gTrue; getIndexVal(subrIdx, k, &val, &ok); if (ok) { cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); } } else { //~ error(-1, "Too few args to Type 2 callsubr"); } // don't clear the stack break; case 0x000b: // return // don't clear the stack break; case 0x000e: // endchar / seac if (firstOp) { cvtGlyphWidth(nOps == 1 || nOps == 5, charBuf, pDict); firstOp = gFalse; } if (openPath) { charBuf->append((char)9); openPath = gFalse; } if (nOps == 4) { cvtNum(0, gFalse, charBuf); cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); charBuf->append((char)12)->append((char)6); } else if (nOps == 0) { charBuf->append((char)14); } else { //~ error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); } nOps = 0; break; case 0x000f: // (obsolete) // this op is ignored, but we need the glyph width if (firstOp) { cvtGlyphWidth(nOps > 0, charBuf, pDict); firstOp = gFalse; } nOps = 0; break; case 0x0010: // blend //~ error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); nOps = 0; break; case 0x0012: // hstemhm // ignored if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); } nHints += nOps / 2; nOps = 0; break; case 0x0013: // hintmask // ignored if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps > 0) { if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", //~ nOps); } nHints += nOps / 2; } pos += (nHints + 7) >> 3; nOps = 0; break; case 0x0014: // cntrmask // ignored if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps > 0) { if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", //~ nOps); } nHints += nOps / 2; } pos += (nHints + 7) >> 3; nOps = 0; break; case 0x0015: // rmoveto if (firstOp) { cvtGlyphWidth(nOps == 3, charBuf, pDict); firstOp = gFalse; } if (openPath) { charBuf->append((char)9); openPath = gFalse; } if (nOps != 2) { //~ error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); charBuf->append((char)21); nOps = 0; break; case 0x0016: // hmoveto if (firstOp) { cvtGlyphWidth(nOps == 2, charBuf, pDict); firstOp = gFalse; } if (openPath) { charBuf->append((char)9); openPath = gFalse; } if (nOps != 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); charBuf->append((char)22); nOps = 0; break; case 0x0017: // vstemhm // ignored if (firstOp) { cvtGlyphWidth(nOps & 1, charBuf, pDict); firstOp = gFalse; } if (nOps & 1) { //~ error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); } nHints += nOps / 2; nOps = 0; break; case 0x0018: // rcurveline if (nOps < 8 || (nOps - 2) % 6 != 0) { //~ error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); } for (k = 0; k < nOps - 2; k += 6) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); charBuf->append((char)8); } cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k].isFP, charBuf); charBuf->append((char)5); nOps = 0; openPath = gTrue; break; case 0x0019: // rlinecurve if (nOps < 8 || (nOps - 6) % 2 != 0) { //~ error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); } for (k = 0; k < nOps - 6; k += 2) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k].isFP, charBuf); charBuf->append((char)5); } cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); cvtNum(ops[k+5].num, ops[k+5].isFP, charBuf); charBuf->append((char)8); nOps = 0; openPath = gTrue; break; case 0x001a: // vvcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { //~ error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); } if (nOps % 2 == 1) { cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[4].num, ops[4].isFP, charBuf); charBuf->append((char)8); k = 5; } else { k = 0; } for (; k < nOps; k += 4) { cvtNum(0, gFalse, charBuf); cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); charBuf->append((char)8); } nOps = 0; openPath = gTrue; break; case 0x001b: // hhcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { //~ error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); } if (nOps % 2 == 1) { cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(ops[4].num, ops[4].isFP, charBuf); cvtNum(0, gFalse, charBuf); charBuf->append((char)8); k = 5; } else { k = 0; } for (; k < nOps; k += 4) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(0, gFalse, charBuf); charBuf->append((char)8); } nOps = 0; openPath = gTrue; break; case 0x001d: // callgsubr if (nOps >= 1) { k = gsubrBias + (int)ops[nOps - 1].num; --nOps; ok = gTrue; getIndexVal(&gsubrIdx, k, &val, &ok); if (ok) { cvtGlyph(val.pos, val.len, charBuf, subrIdx, pDict, gFalse); } } else { //~ error(-1, "Too few args to Type 2 callgsubr"); } // don't clear the stack break; case 0x001e: // vhcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { //~ error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); } for (k = 0; k < nOps && k != nOps-5; k += 4) { if (k % 8 == 0) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); charBuf->append((char)30); } else { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); charBuf->append((char)31); } } if (k == nOps-5) { if (k % 8 == 0) { cvtNum(0, gFalse, charBuf); cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); } else { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); } charBuf->append((char)8); } nOps = 0; openPath = gTrue; break; case 0x001f: // hvcurveto if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { //~ error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); } for (k = 0; k < nOps && k != nOps-5; k += 4) { if (k % 8 == 0) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); charBuf->append((char)31); } else { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); charBuf->append((char)30); } } if (k == nOps-5) { if (k % 8 == 0) { cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); } else { cvtNum(0, gFalse, charBuf); cvtNum(ops[k].num, ops[k].isFP, charBuf); cvtNum(ops[k+1].num, ops[k+1].isFP, charBuf); cvtNum(ops[k+2].num, ops[k+2].isFP, charBuf); cvtNum(ops[k+3].num, ops[k+3].isFP, charBuf); cvtNum(ops[k+4].num, ops[k+4].isFP, charBuf); } charBuf->append((char)8); } nOps = 0; openPath = gTrue; break; case 0x0c00: // dotsection (should be Type 1 only?) // ignored nOps = 0; break; case 0x0c03: // and case 0x0c04: // or case 0x0c05: // not case 0x0c08: // store case 0x0c09: // abs case 0x0c0a: // add case 0x0c0b: // sub case 0x0c0c: // div case 0x0c0d: // load case 0x0c0e: // neg case 0x0c0f: // eq case 0x0c12: // drop case 0x0c14: // put case 0x0c15: // get case 0x0c16: // ifelse case 0x0c17: // random case 0x0c18: // mul case 0x0c1a: // sqrt case 0x0c1b: // dup case 0x0c1c: // exch case 0x0c1d: // index case 0x0c1e: // roll //~ error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); nOps = 0; break; case 0x0c22: // hflex if (nOps != 7) { //~ error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(0, gFalse, charBuf); charBuf->append((char)8); cvtNum(ops[4].num, ops[4].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[5].num, ops[5].isFP, charBuf); cvtNum(-ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[6].num, ops[6].isFP, charBuf); cvtNum(0, gFalse, charBuf); charBuf->append((char)8); nOps = 0; openPath = gTrue; break; case 0x0c23: // flex if (nOps != 13) { //~ error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(ops[4].num, ops[4].isFP, charBuf); cvtNum(ops[5].num, ops[5].isFP, charBuf); charBuf->append((char)8); cvtNum(ops[6].num, ops[6].isFP, charBuf); cvtNum(ops[7].num, ops[7].isFP, charBuf); cvtNum(ops[8].num, ops[8].isFP, charBuf); cvtNum(ops[9].num, ops[9].isFP, charBuf); cvtNum(ops[10].num, ops[10].isFP, charBuf); cvtNum(ops[11].num, ops[11].isFP, charBuf); charBuf->append((char)8); nOps = 0; openPath = gTrue; break; case 0x0c24: // hflex1 if (nOps != 9) { //~ error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(ops[4].num, ops[4].isFP, charBuf); cvtNum(0, gFalse, charBuf); charBuf->append((char)8); cvtNum(ops[5].num, ops[5].isFP, charBuf); cvtNum(0, gFalse, charBuf); cvtNum(ops[6].num, ops[6].isFP, charBuf); cvtNum(ops[7].num, ops[7].isFP, charBuf); cvtNum(ops[8].num, ops[8].isFP, charBuf); cvtNum(-(ops[1].num + ops[3].num + ops[7].num), ops[1].isFP | ops[3].isFP | ops[7].isFP, charBuf); charBuf->append((char)8); nOps = 0; openPath = gTrue; break; case 0x0c25: // flex1 if (nOps != 11) { //~ error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); } cvtNum(ops[0].num, ops[0].isFP, charBuf); cvtNum(ops[1].num, ops[1].isFP, charBuf); cvtNum(ops[2].num, ops[2].isFP, charBuf); cvtNum(ops[3].num, ops[3].isFP, charBuf); cvtNum(ops[4].num, ops[4].isFP, charBuf); cvtNum(ops[5].num, ops[5].isFP, charBuf); charBuf->append((char)8); cvtNum(ops[6].num, ops[6].isFP, charBuf); cvtNum(ops[7].num, ops[7].isFP, charBuf); cvtNum(ops[8].num, ops[8].isFP, charBuf); cvtNum(ops[9].num, ops[9].isFP, charBuf); dx = ops[0].num + ops[2].num + ops[4].num + ops[6].num + ops[8].num; dy = ops[1].num + ops[3].num + ops[5].num + ops[7].num + ops[9].num; if (fabs(dx) > fabs(dy)) { cvtNum(ops[10].num, ops[10].isFP, charBuf); cvtNum(-dy, ops[1].isFP | ops[3].isFP | ops[5].isFP | ops[7].isFP | ops[9].isFP, charBuf); } else { cvtNum(-dx, ops[0].isFP | ops[2].isFP | ops[4].isFP | ops[6].isFP | ops[8].isFP, charBuf); cvtNum(ops[10].num, ops[10].isFP, charBuf); } charBuf->append((char)8); nOps = 0; openPath = gTrue; break; default: //~ error(-1, "Illegal Type 2 charstring op: %04x", //~ ops[nOps].op); nOps = 0; break; } } } // charstring encryption if (top) { r2 = 4330; for (i = start; i < charBuf->getLength(); ++i) { byte = charBuf->getChar(i) ^ (r2 >> 8); charBuf->setChar(i, byte); r2 = (byte + r2) * 52845 + 22719; } } } void FoFiType1C::cvtGlyphWidth(GBool useOp, GString *charBuf, Type1CPrivateDict *pDict) { double w; GBool wFP; int i; if (useOp) { w = pDict->nominalWidthX + ops[0].num; wFP = pDict->nominalWidthXFP | ops[0].isFP; for (i = 1; i < nOps; ++i) { ops[i-1] = ops[i]; } --nOps; } else { w = pDict->defaultWidthX; wFP = pDict->defaultWidthXFP; } cvtNum(0, gFalse, charBuf); cvtNum(w, wFP, charBuf); charBuf->append((char)13); } void FoFiType1C::cvtNum(double x, GBool isFP, GString *charBuf) { Guchar buf[12]; int y, n; n = 0; if (isFP) { if (x >= -32768 && x < 32768) { y = (int)(x * 256.0); buf[0] = 255; buf[1] = (Guchar)(y >> 24); buf[2] = (Guchar)(y >> 16); buf[3] = (Guchar)(y >> 8); buf[4] = (Guchar)y; buf[5] = 255; buf[6] = 0; buf[7] = 0; buf[8] = 1; buf[9] = 0; buf[10] = 12; buf[11] = 12; n = 12; } else { //~ error(-1, "Type 2 fixed point constant out of range"); } } else { y = (int)x; if (y >= -107 && y <= 107) { buf[0] = (Guchar)(y + 139); n = 1; } else if (y > 107 && y <= 1131) { y -= 108; buf[0] = (Guchar)((y >> 8) + 247); buf[1] = (Guchar)(y & 0xff); n = 2; } else if (y < -107 && y >= -1131) { y = -y - 108; buf[0] = (Guchar)((y >> 8) + 251); buf[1] = (Guchar)(y & 0xff); n = 2; } else { buf[0] = 255; buf[1] = (Guchar)(y >> 24); buf[2] = (Guchar)(y >> 16); buf[3] = (Guchar)(y >> 8); buf[4] = (Guchar)y; n = 5; } } charBuf->append((char *)buf, n); } void FoFiType1C::eexecWrite(Type1CEexecBuf *eb, const char *s) { Guchar *p; Guchar x; for (p = (Guchar *)s; *p; ++p) { x = *p ^ (eb->r1 >> 8); eb->r1 = (x + eb->r1) * 52845 + 22719; if (eb->ascii) { (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); eb->line += 2; if (eb->line == 64) { (*eb->outputFunc)(eb->outputStream, "\n", 1); eb->line = 0; } } else { (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); } } } void FoFiType1C::eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n) { Guchar x; int i; // eexec encryption for (i = 0; i < n; ++i) { x = s[i] ^ (eb->r1 >> 8); eb->r1 = (x + eb->r1) * 52845 + 22719; if (eb->ascii) { (*eb->outputFunc)(eb->outputStream, &hexChars[x >> 4], 1); (*eb->outputFunc)(eb->outputStream, &hexChars[x & 0x0f], 1); eb->line += 2; if (eb->line == 64) { (*eb->outputFunc)(eb->outputStream, "\n", 1); eb->line = 0; } } else { (*eb->outputFunc)(eb->outputStream, (char *)&x, 1); } } } void FoFiType1C::writePSString(char *s, FoFiOutputFunc outputFunc, void *outputStream) { char buf[80]; char *p; int i, c; i = 0; buf[i++] = '('; for (p = s; *p; ++p) { c = *p & 0xff; if (c == '(' || c == ')' || c == '\\') { buf[i++] = '\\'; buf[i++] = c; } else if (c < 0x20 || c >= 0x80) { buf[i++] = '\\'; buf[i++] = '0' + ((c >> 6) & 7); buf[i++] = '0' + ((c >> 3) & 7); buf[i++] = '0' + (c & 7); } else { buf[i++] = c; } if (i >= 64) { buf[i++] = '\\'; buf[i++] = '\n'; (*outputFunc)(outputStream, buf, i); i = 0; } } buf[i++] = ')'; (*outputFunc)(outputStream, buf, i); } GBool FoFiType1C::parse() { Type1CIndex fdIdx; Type1CIndexVal val; int i; parsedOk = gTrue; // some tools embed Type 1C fonts with an extra whitespace char at // the beginning if (len > 0 && file[0] != '\x01') { ++file; --len; } // find the indexes getIndex(getU8(2, &parsedOk), &nameIdx, &parsedOk); getIndex(nameIdx.endPos, &topDictIdx, &parsedOk); getIndex(topDictIdx.endPos, &stringIdx, &parsedOk); getIndex(stringIdx.endPos, &gsubrIdx, &parsedOk); if (!parsedOk) { return gFalse; } gsubrBias = (gsubrIdx.len < 1240) ? 107 : (gsubrIdx.len < 33900) ? 1131 : 32768; // read the first font name getIndexVal(&nameIdx, 0, &val, &parsedOk); if (!parsedOk) { return gFalse; } name = new GString((char *)&file[val.pos], val.len); // read the top dict for the first font readTopDict(); // for CID fonts: read the FDArray dicts and private dicts if (topDict.firstOp == 0x0c1e) { if (topDict.fdArrayOffset == 0) { nFDs = 1; privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); readPrivateDict(0, 0, &privateDicts[0]); } else { getIndex(topDict.fdArrayOffset, &fdIdx, &parsedOk); if (!parsedOk) { return gFalse; } nFDs = fdIdx.len; privateDicts = (Type1CPrivateDict *) gmallocn(nFDs, sizeof(Type1CPrivateDict)); for (i = 0; i < nFDs; ++i) { getIndexVal(&fdIdx, i, &val, &parsedOk); if (!parsedOk) { return gFalse; } readFD(val.pos, val.len, &privateDicts[i]); } } // for 8-bit fonts: read the private dict } else { nFDs = 1; privateDicts = (Type1CPrivateDict *)gmalloc(sizeof(Type1CPrivateDict)); readPrivateDict(topDict.privateOffset, topDict.privateSize, &privateDicts[0]); } // check for parse errors in the private dict(s) if (!parsedOk) { return gFalse; } // get the charstrings index if (topDict.charStringsOffset <= 0) { parsedOk = gFalse; return gFalse; } getIndex(topDict.charStringsOffset, &charStringsIdx, &parsedOk); if (!parsedOk) { return gFalse; } nGlyphs = charStringsIdx.len; // for CID fonts: read the FDSelect table if (topDict.firstOp == 0x0c1e) { readFDSelect(); if (!parsedOk) { return gFalse; } } // read the charset if (!readCharset()) { parsedOk = gFalse; return gFalse; } // for 8-bit fonts: build the encoding if (topDict.firstOp != 0x0c14 && topDict.firstOp != 0x0c1e) { buildEncoding(); if (!parsedOk) { return gFalse; } } return parsedOk; } void FoFiType1C::readTopDict() { Type1CIndexVal topDictPtr; int pos; topDict.firstOp = -1; topDict.versionSID = 0; topDict.noticeSID = 0; topDict.copyrightSID = 0; topDict.fullNameSID = 0; topDict.familyNameSID = 0; topDict.weightSID = 0; topDict.isFixedPitch = 0; topDict.italicAngle = 0; topDict.underlinePosition = -100; topDict.underlineThickness = 50; topDict.paintType = 0; topDict.charstringType = 2; topDict.fontMatrix[0] = 0.001; topDict.fontMatrix[1] = 0; topDict.fontMatrix[2] = 0; topDict.fontMatrix[3] = 0.001; topDict.fontMatrix[4] = 0; topDict.fontMatrix[5] = 0; topDict.hasFontMatrix = gFalse; topDict.uniqueID = 0; topDict.fontBBox[0] = 0; topDict.fontBBox[1] = 0; topDict.fontBBox[2] = 0; topDict.fontBBox[3] = 0; topDict.strokeWidth = 0; topDict.charsetOffset = 0; topDict.encodingOffset = 0; topDict.charStringsOffset = 0; topDict.privateSize = 0; topDict.privateOffset = 0; topDict.registrySID = 0; topDict.orderingSID = 0; topDict.supplement = 0; topDict.fdArrayOffset = 0; topDict.fdSelectOffset = 0; getIndexVal(&topDictIdx, 0, &topDictPtr, &parsedOk); pos = topDictPtr.pos; nOps = 0; while (pos < topDictPtr.pos + topDictPtr.len) { pos = getOp(pos, gFalse, &parsedOk); if (!parsedOk) { break; } if (!ops[nOps - 1].isNum) { --nOps; // drop the operator if (topDict.firstOp < 0) { topDict.firstOp = ops[nOps].op; } switch (ops[nOps].op) { case 0x0000: topDict.versionSID = (int)ops[0].num; break; case 0x0001: topDict.noticeSID = (int)ops[0].num; break; case 0x0c00: topDict.copyrightSID = (int)ops[0].num; break; case 0x0002: topDict.fullNameSID = (int)ops[0].num; break; case 0x0003: topDict.familyNameSID = (int)ops[0].num; break; case 0x0004: topDict.weightSID = (int)ops[0].num; break; case 0x0c01: topDict.isFixedPitch = (int)ops[0].num; break; case 0x0c02: topDict.italicAngle = ops[0].num; break; case 0x0c03: topDict.underlinePosition = ops[0].num; break; case 0x0c04: topDict.underlineThickness = ops[0].num; break; case 0x0c05: topDict.paintType = (int)ops[0].num; break; case 0x0c06: topDict.charstringType = (int)ops[0].num; break; case 0x0c07: topDict.fontMatrix[0] = ops[0].num; topDict.fontMatrix[1] = ops[1].num; topDict.fontMatrix[2] = ops[2].num; topDict.fontMatrix[3] = ops[3].num; topDict.fontMatrix[4] = ops[4].num; topDict.fontMatrix[5] = ops[5].num; topDict.hasFontMatrix = gTrue; break; case 0x000d: topDict.uniqueID = (int)ops[0].num; break; case 0x0005: topDict.fontBBox[0] = ops[0].num; topDict.fontBBox[1] = ops[1].num; topDict.fontBBox[2] = ops[2].num; topDict.fontBBox[3] = ops[3].num; break; case 0x0c08: topDict.strokeWidth = ops[0].num; break; case 0x000f: topDict.charsetOffset = (int)ops[0].num; break; case 0x0010: topDict.encodingOffset = (int)ops[0].num; break; case 0x0011: topDict.charStringsOffset = (int)ops[0].num; break; case 0x0012: topDict.privateSize = (int)ops[0].num; topDict.privateOffset = (int)ops[1].num; break; case 0x0c1e: topDict.registrySID = (int)ops[0].num; topDict.orderingSID = (int)ops[1].num; topDict.supplement = (int)ops[2].num; break; case 0x0c24: topDict.fdArrayOffset = (int)ops[0].num; break; case 0x0c25: topDict.fdSelectOffset = (int)ops[0].num; break; } nOps = 0; } } } // Read a CID font dict (FD) - this pulls out the private dict // pointer, and reads the private dict. It also pulls the FontMatrix // (if any) out of the FD. void FoFiType1C::readFD(int offset, int length, Type1CPrivateDict *pDict) { int pos, pSize, pOffset; double fontMatrix[6]; GBool hasFontMatrix; hasFontMatrix = gFalse; fontMatrix[0] = fontMatrix[1] = fontMatrix[2] = 0; // make gcc happy fontMatrix[3] = fontMatrix[4] = fontMatrix[5] = 0; pSize = pOffset = 0; pos = offset; nOps = 0; while (pos < offset + length) { pos = getOp(pos, gFalse, &parsedOk); if (!parsedOk) { return; } if (!ops[nOps - 1].isNum) { if (ops[nOps - 1].op == 0x0012) { if (nOps < 3) { parsedOk = gFalse; return; } pSize = (int)ops[0].num; pOffset = (int)ops[1].num; break; } else if (ops[nOps - 1].op == 0x0c07) { fontMatrix[0] = ops[0].num; fontMatrix[1] = ops[1].num; fontMatrix[2] = ops[2].num; fontMatrix[3] = ops[3].num; fontMatrix[4] = ops[4].num; fontMatrix[5] = ops[5].num; hasFontMatrix = gTrue; } nOps = 0; } } readPrivateDict(pOffset, pSize, pDict); if (hasFontMatrix) { pDict->fontMatrix[0] = fontMatrix[0]; pDict->fontMatrix[1] = fontMatrix[1]; pDict->fontMatrix[2] = fontMatrix[2]; pDict->fontMatrix[3] = fontMatrix[3]; pDict->fontMatrix[4] = fontMatrix[4]; pDict->fontMatrix[5] = fontMatrix[5]; pDict->hasFontMatrix = gTrue; } } void FoFiType1C::readPrivateDict(int offset, int length, Type1CPrivateDict *pDict) { int pos; pDict->hasFontMatrix = gFalse; pDict->nBlueValues = 0; pDict->nOtherBlues = 0; pDict->nFamilyBlues = 0; pDict->nFamilyOtherBlues = 0; pDict->blueScale = 0.039625; pDict->blueShift = 7; pDict->blueFuzz = 1; pDict->hasStdHW = gFalse; pDict->hasStdVW = gFalse; pDict->nStemSnapH = 0; pDict->nStemSnapV = 0; pDict->hasForceBold = gFalse; pDict->forceBoldThreshold = 0; pDict->languageGroup = 0; pDict->expansionFactor = 0.06; pDict->initialRandomSeed = 0; pDict->subrsOffset = 0; pDict->defaultWidthX = 0; pDict->defaultWidthXFP = gFalse; pDict->nominalWidthX = 0; pDict->nominalWidthXFP = gFalse; // no dictionary if (offset == 0 || length == 0) { return; } pos = offset; nOps = 0; while (pos < offset + length) { pos = getOp(pos, gFalse, &parsedOk); if (!parsedOk) { break; } if (!ops[nOps - 1].isNum) { --nOps; // drop the operator switch (ops[nOps].op) { case 0x0006: pDict->nBlueValues = getDeltaIntArray(pDict->blueValues, type1CMaxBlueValues); break; case 0x0007: pDict->nOtherBlues = getDeltaIntArray(pDict->otherBlues, type1CMaxOtherBlues); break; case 0x0008: pDict->nFamilyBlues = getDeltaIntArray(pDict->familyBlues, type1CMaxBlueValues); break; case 0x0009: pDict->nFamilyOtherBlues = getDeltaIntArray(pDict->familyOtherBlues, type1CMaxOtherBlues); break; case 0x0c09: pDict->blueScale = ops[0].num; break; case 0x0c0a: pDict->blueShift = (int)ops[0].num; break; case 0x0c0b: pDict->blueFuzz = (int)ops[0].num; break; case 0x000a: pDict->stdHW = ops[0].num; pDict->hasStdHW = gTrue; break; case 0x000b: pDict->stdVW = ops[0].num; pDict->hasStdVW = gTrue; break; case 0x0c0c: pDict->nStemSnapH = getDeltaFPArray(pDict->stemSnapH, type1CMaxStemSnap); break; case 0x0c0d: pDict->nStemSnapV = getDeltaFPArray(pDict->stemSnapV, type1CMaxStemSnap); break; case 0x0c0e: pDict->forceBold = ops[0].num != 0; pDict->hasForceBold = gTrue; break; case 0x0c0f: pDict->forceBoldThreshold = ops[0].num; break; case 0x0c11: pDict->languageGroup = (int)ops[0].num; break; case 0x0c12: pDict->expansionFactor = ops[0].num; break; case 0x0c13: pDict->initialRandomSeed = (int)ops[0].num; break; case 0x0013: pDict->subrsOffset = offset + (int)ops[0].num; break; case 0x0014: pDict->defaultWidthX = ops[0].num; pDict->defaultWidthXFP = ops[0].isFP; break; case 0x0015: pDict->nominalWidthX = ops[0].num; pDict->nominalWidthXFP = ops[0].isFP; break; } nOps = 0; } } } void FoFiType1C::readFDSelect() { int fdSelectFmt, pos, nRanges, gid0, gid1, fd, i, j; fdSelect = (Guchar *)gmalloc(nGlyphs); if (topDict.fdSelectOffset == 0) { for (i = 0; i < nGlyphs; ++i) { fdSelect[i] = 0; } } else { pos = topDict.fdSelectOffset; fdSelectFmt = getU8(pos++, &parsedOk); if (!parsedOk) { return; } if (fdSelectFmt == 0) { if (!checkRegion(pos, nGlyphs)) { parsedOk = gFalse; return; } memcpy(fdSelect, file + pos, nGlyphs); } else if (fdSelectFmt == 3) { nRanges = getU16BE(pos, &parsedOk); pos += 2; gid0 = getU16BE(pos, &parsedOk); pos += 2; for (i = 1; i <= nRanges; ++i) { fd = getU8(pos++, &parsedOk); gid1 = getU16BE(pos, &parsedOk); if (!parsedOk) { return; } pos += 2; if (gid0 > gid1 || gid1 > nGlyphs) { //~ error(-1, "Bad FDSelect table in CID font"); parsedOk = gFalse; return; } for (j = gid0; j < gid1; ++j) { fdSelect[j] = fd; } gid0 = gid1; } } else { //~ error(-1, "Unknown FDSelect table format in CID font"); for (i = 0; i < nGlyphs; ++i) { fdSelect[i] = 0; } } } } void FoFiType1C::buildEncoding() { char buf[256]; int nCodes, nRanges, encFormat; int pos, c, sid, nLeft, nSups, i, j; if (topDict.encodingOffset == 0) { encoding = (char **)fofiType1StandardEncoding; } else if (topDict.encodingOffset == 1) { encoding = (char **)fofiType1ExpertEncoding; } else { encoding = (char **)gmallocn(256, sizeof(char *)); for (i = 0; i < 256; ++i) { encoding[i] = NULL; } pos = topDict.encodingOffset; encFormat = getU8(pos++, &parsedOk); if (!parsedOk) { return; } if ((encFormat & 0x7f) == 0) { nCodes = 1 + getU8(pos++, &parsedOk); if (!parsedOk) { return; } if (nCodes > nGlyphs) { nCodes = nGlyphs; } for (i = 1; i < nCodes; ++i) { c = getU8(pos++, &parsedOk); if (!parsedOk) { return; } if (encoding[c]) { gfree(encoding[c]); } encoding[c] = copyString(getString(charset[i], buf, &parsedOk)); } } else if ((encFormat & 0x7f) == 1) { nRanges = getU8(pos++, &parsedOk); if (!parsedOk) { return; } nCodes = 1; for (i = 0; i < nRanges; ++i) { c = getU8(pos++, &parsedOk); nLeft = getU8(pos++, &parsedOk); if (!parsedOk) { return; } for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { if (c < 256) { if (encoding[c]) { gfree(encoding[c]); } encoding[c] = copyString(getString(charset[nCodes], buf, &parsedOk)); } ++nCodes; ++c; } } } if (encFormat & 0x80) { nSups = getU8(pos++, &parsedOk); if (!parsedOk) { return; } for (i = 0; i < nSups; ++i) { c = getU8(pos++, &parsedOk);; if (!parsedOk) { return;; } sid = getU16BE(pos, &parsedOk); pos += 2; if (!parsedOk) { return; } if (encoding[c]) { gfree(encoding[c]); } encoding[c] = copyString(getString(sid, buf, &parsedOk)); } } } } GBool FoFiType1C::readCharset() { int charsetFormat, c, pos; int nLeft, i, j; if (topDict.charsetOffset == 0) { charset = fofiType1CISOAdobeCharset; } else if (topDict.charsetOffset == 1) { charset = fofiType1CExpertCharset; } else if (topDict.charsetOffset == 2) { charset = fofiType1CExpertSubsetCharset; } else { charset = (Gushort *)gmallocn(nGlyphs, sizeof(Gushort)); for (i = 0; i < nGlyphs; ++i) { charset[i] = 0; } pos = topDict.charsetOffset; charsetFormat = getU8(pos++, &parsedOk); if (charsetFormat == 0) { for (i = 1; i < nGlyphs; ++i) { charset[i] = (Gushort)getU16BE(pos, &parsedOk); pos += 2; if (!parsedOk) { break; } } } else if (charsetFormat == 1) { i = 1; while (i < nGlyphs) { c = getU16BE(pos, &parsedOk); pos += 2; nLeft = getU8(pos++, &parsedOk); if (!parsedOk) { break; } for (j = 0; j <= nLeft && i < nGlyphs; ++j) { charset[i++] = (Gushort)c++; } } } else if (charsetFormat == 2) { i = 1; while (i < nGlyphs) { c = getU16BE(pos, &parsedOk); pos += 2; nLeft = getU16BE(pos, &parsedOk); pos += 2; if (!parsedOk) { break; } for (j = 0; j <= nLeft && i < nGlyphs; ++j) { charset[i++] = (Gushort)c++; } } } if (!parsedOk) { gfree(charset); charset = NULL; return gFalse; } } return gTrue; } int FoFiType1C::getOp(int pos, GBool charstring, GBool *ok) { static char nybChars[16] = "0123456789.ee -"; Type1COp op; char buf[65]; int b0, b1, nyb0, nyb1, x, i; b0 = getU8(pos++, ok); op.isNum = gTrue; op.isFP = gFalse; if (b0 == 28) { x = getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); if (x & 0x8000) { x |= ~0xffff; } op.num = x; } else if (!charstring && b0 == 29) { x = getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); if (x & 0x80000000) { x |= ~0xffffffff; } op.num = x; } else if (!charstring && b0 == 30) { i = 0; do { b1 = getU8(pos++, ok); nyb0 = b1 >> 4; nyb1 = b1 & 0x0f; if (nyb0 == 0xf) { break; } buf[i++] = nybChars[nyb0]; if (i == 64) { break; } if (nyb0 == 0xc) { buf[i++] = '-'; } if (i == 64) { break; } if (nyb1 == 0xf) { break; } buf[i++] = nybChars[nyb1]; if (i == 64) { break; } if (nyb1 == 0xc) { buf[i++] = '-'; } } while (i < 64); buf[i] = '\0'; op.num = atof(buf); op.isFP = gTrue; } else if (b0 >= 32 && b0 <= 246) { op.num = b0 - 139; } else if (b0 >= 247 && b0 <= 250) { op.num = ((b0 - 247) << 8) + getU8(pos++, ok) + 108; } else if (b0 >= 251 && b0 <= 254) { op.num = -((b0 - 251) << 8) - getU8(pos++, ok) - 108; } else if (charstring && b0 == 255) { x = getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); x = (x << 8) | getU8(pos++, ok); if (x & 0x80000000) { x |= ~0xffffffff; } op.num = (double)x / 65536.0; op.isFP = gTrue; } else if (b0 == 12) { op.isNum = gFalse; op.op = 0x0c00 + getU8(pos++, ok); } else { op.isNum = gFalse; op.op = b0; } if (nOps < 49) { ops[nOps++] = op; } return pos; } // Convert the delta-encoded ops array to an array of ints. int FoFiType1C::getDeltaIntArray(int *arr, int maxLen) { int x; int n, i; if ((n = nOps) > maxLen) { n = maxLen; } x = 0; for (i = 0; i < n; ++i) { x += (int)ops[i].num; arr[i] = x; } return n; } // Convert the delta-encoded ops array to an array of doubles. int FoFiType1C::getDeltaFPArray(double *arr, int maxLen) { double x; int n, i; if ((n = nOps) > maxLen) { n = maxLen; } x = 0; for (i = 0; i < n; ++i) { x += ops[i].num; arr[i] = x; } return n; } void FoFiType1C::getIndex(int pos, Type1CIndex *idx, GBool *ok) { idx->pos = pos; idx->len = getU16BE(pos, ok); if (idx->len == 0) { // empty indexes are legal and contain just the length field idx->offSize = 0; idx->startPos = idx->endPos = pos + 2; } else { idx->offSize = getU8(pos + 2, ok); if (idx->offSize < 1 || idx->offSize > 4) { *ok = gFalse; } idx->startPos = pos + 3 + (idx->len + 1) * idx->offSize - 1; if (idx->startPos < 0 || idx->startPos >= len) { *ok = gFalse; } idx->endPos = idx->startPos + getUVarBE(pos + 3 + idx->len * idx->offSize, idx->offSize, ok); if (idx->endPos < idx->startPos || idx->endPos > len) { *ok = gFalse; } } } void FoFiType1C::getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok) { int pos0, pos1; if (i < 0 || i >= idx->len) { *ok = gFalse; return; } pos0 = idx->startPos + getUVarBE(idx->pos + 3 + i * idx->offSize, idx->offSize, ok); pos1 = idx->startPos + getUVarBE(idx->pos + 3 + (i + 1) * idx->offSize, idx->offSize, ok); if (pos0 < idx->startPos || pos0 > idx->endPos || pos1 <= idx->startPos || pos1 > idx->endPos || pos1 < pos0) { *ok = gFalse; } val->pos = pos0; val->len = pos1 - pos0; } char *FoFiType1C::getString(int sid, char *buf, GBool *ok) { Type1CIndexVal val; int n; if (sid < 0) { buf[0] = '\0'; } else if (sid < 391) { strcpy(buf, fofiType1CStdStrings[sid]); } else { sid -= 391; getIndexVal(&stringIdx, sid, &val, ok); if (*ok) { if ((n = val.len) > 255) { n = 255; } strncpy(buf, (char *)&file[val.pos], n); buf[n] = '\0'; } else { buf[0] = '\0'; } } return buf; } xpdf-3.03/fofi/FoFiIdentifier.h0000644000076400007640000000234111622305345015635 0ustar dereknderekn//======================================================================== // // FoFiIdentifier.h // // Copyright 2009 Glyph & Cog, LLC // //======================================================================== #ifndef FOFIIDENTIFIER_H #define FOFIIDENTIFIER_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif //------------------------------------------------------------------------ // FoFiIdentifier //------------------------------------------------------------------------ enum FoFiIdentifierType { fofiIdType1PFA, // Type 1 font in PFA format fofiIdType1PFB, // Type 1 font in PFB format fofiIdCFF8Bit, // 8-bit CFF font fofiIdCFFCID, // CID CFF font fofiIdTrueType, // TrueType font fofiIdTrueTypeCollection, // TrueType collection fofiIdOpenTypeCFF8Bit, // OpenType wrapper with 8-bit CFF font fofiIdOpenTypeCFFCID, // OpenType wrapper with CID CFF font fofiIdUnknown, // unknown type fofiIdError // error in reading the file }; class FoFiIdentifier { public: static FoFiIdentifierType identifyMem(char *file, int len); static FoFiIdentifierType identifyFile(char *fileName); static FoFiIdentifierType identifyStream(int (*getChar)(void *data), void *data); }; #endif xpdf-3.03/fofi/Makefile.in0000644000076400007640000000275511622305345014714 0ustar dereknderekn#======================================================================== # # FoFi library Makefile # # Copyright 2003 Glyph & Cog, LLC # #======================================================================== SHELL = /bin/sh srcdir = @srcdir@ VPATH = @srcdir@ GOOSRCDIR = $(srcdir)/../goo GOOLIBDIR = ../goo CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(srcdir) CXX = @CXX@ AR = @AR@ RANLIB = @RANLIB@ LIBPREFIX = @LIBPREFIX@ #------------------------------------------------------------------------ .SUFFIXES: .cc .cc.o: $(CXX) $(CXXFLAGS) -c $< #------------------------------------------------------------------------ CXX_SRC = \ $(srcdir)/FoFiBase.cc \ $(srcdir)/FoFiEncodings.cc \ $(srcdir)/FoFiIdentifier.cc \ $(srcdir)/FoFiTrueType.cc \ $(srcdir)/FoFiType1.cc \ $(srcdir)/FoFiType1C.cc #------------------------------------------------------------------------ all: $(LIBPREFIX)fofi.a #------------------------------------------------------------------------ FOFI_OBJS = \ FoFiBase.o \ FoFiEncodings.o \ FoFiIdentifier.o \ FoFiTrueType.o \ FoFiType1.o \ FoFiType1C.o $(LIBPREFIX)fofi.a: $(FOFI_OBJS) rm -f $(LIBPREFIX)fofi.a $(AR) $(LIBPREFIX)fofi.a $(FOFI_OBJS) $(RANLIB) $(LIBPREFIX)fofi.a #------------------------------------------------------------------------ clean: rm -f $(FOFI_OBJS) $(LIBPREFIX)fofi.a #------------------------------------------------------------------------ depend: $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep include Makefile.dep xpdf-3.03/fofi/FoFiType1.cc0000644000076400007640000001750311622305345014721 0ustar dereknderekn//======================================================================== // // FoFiType1.cc // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "FoFiEncodings.h" #include "FoFiType1.h" //------------------------------------------------------------------------ // FoFiType1 //------------------------------------------------------------------------ FoFiType1 *FoFiType1::make(char *fileA, int lenA) { return new FoFiType1(fileA, lenA, gFalse); } FoFiType1 *FoFiType1::load(char *fileName) { char *fileA; int lenA; if (!(fileA = FoFiBase::readFile(fileName, &lenA))) { return NULL; } return new FoFiType1(fileA, lenA, gTrue); } FoFiType1::FoFiType1(char *fileA, int lenA, GBool freeFileDataA): FoFiBase(fileA, lenA, freeFileDataA) { name = NULL; encoding = NULL; fontMatrix[0] = 0.001; fontMatrix[1] = 0; fontMatrix[2] = 0; fontMatrix[3] = 0.001; fontMatrix[4] = 0; fontMatrix[5] = 0; parsed = gFalse; undoPFB(); } FoFiType1::~FoFiType1() { int i; if (name) { gfree(name); } if (encoding && encoding != (char **)fofiType1StandardEncoding) { for (i = 0; i < 256; ++i) { gfree(encoding[i]); } gfree(encoding); } } char *FoFiType1::getName() { if (!parsed) { parse(); } return name; } char **FoFiType1::getEncoding() { if (!parsed) { parse(); } return encoding; } void FoFiType1::getFontMatrix(double *mat) { int i; if (!parsed) { parse(); } for (i = 0; i < 6; ++i) { mat[i] = fontMatrix[i]; } } void FoFiType1::writeEncoded(const char **newEncoding, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; char *line, *line2, *p; int i; // copy everything up to the encoding for (line = (char *)file; line && strncmp(line, "/Encoding", 9); line = getNextLine(line)) ; if (!line) { // no encoding - just copy the whole font file (*outputFunc)(outputStream, (char *)file, len); return; } (*outputFunc)(outputStream, (char *)file, (int)(line - (char *)file)); // write the new encoding (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); (*outputFunc)(outputStream, "0 1 255 {1 index exch /.notdef put} for\n", 40); for (i = 0; i < 256; ++i) { if (newEncoding[i]) { sprintf(buf, "dup %d /%s put\n", i, newEncoding[i]); (*outputFunc)(outputStream, buf, (int)strlen(buf)); } } (*outputFunc)(outputStream, "readonly def\n", 13); // find the end of the encoding data //~ this ought to parse PostScript tokens if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { line = getNextLine(line); } else { // skip "/Encoding" + one whitespace char, // then look for 'def' preceded by PostScript whitespace p = line + 10; line = NULL; for (; p < (char *)file + len; ++p) { if ((*p == ' ' || *p == '\t' || *p == '\x0a' || *p == '\x0d' || *p == '\x0c' || *p == '\0') && p + 4 <= (char *)file + len && !strncmp(p + 1, "def", 3)) { line = p + 4; break; } } } // some fonts have two /Encoding entries in their dictionary, so we // check for a second one here if (line) { for (line2 = line, i = 0; i < 20 && line2 && strncmp(line2, "/Encoding", 9); line2 = getNextLine(line2), ++i) ; if (i < 20 && line2) { (*outputFunc)(outputStream, line, (int)(line2 - line)); if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) { line = getNextLine(line2); } else { // skip "/Encoding" + one whitespace char, // then look for 'def' preceded by PostScript whitespace p = line2 + 10; line = NULL; for (; p < (char *)file + len; ++p) { if ((*p == ' ' || *p == '\t' || *p == '\x0a' || *p == '\x0d' || *p == '\x0c' || *p == '\0') && p + 4 <= (char *)file + len && !strncmp(p + 1, "def", 3)) { line = p + 4; break; } } } } // copy everything after the encoding if (line) { (*outputFunc)(outputStream, line, (int)(((char *)file + len) - line)); } } } char *FoFiType1::getNextLine(char *line) { while (line < (char *)file + len && *line != '\x0a' && *line != '\x0d') { ++line; } if (line < (char *)file + len && *line == '\x0d') { ++line; } if (line < (char *)file + len && *line == '\x0a') { ++line; } if (line >= (char *)file + len) { return NULL; } return line; } void FoFiType1::parse() { char *line, *line1, *p, *p2; char buf[256]; char c; int n, code, base, i, j; GBool gotMatrix; gotMatrix = gFalse; for (i = 1, line = (char *)file; i <= 100 && line && (!name || !encoding); ++i) { // get font name if (!name && !strncmp(line, "/FontName", 9)) { strncpy(buf, line, 255); buf[255] = '\0'; if ((p = strchr(buf+9, '/')) && (p = strtok(p+1, " \t\n\r"))) { name = copyString(p); } line = getNextLine(line); // get encoding } else if (!encoding && !strncmp(line, "/Encoding StandardEncoding def", 30)) { encoding = (char **)fofiType1StandardEncoding; } else if (!encoding && !strncmp(line, "/Encoding 256 array", 19)) { encoding = (char **)gmallocn(256, sizeof(char *)); for (j = 0; j < 256; ++j) { encoding[j] = NULL; } for (j = 0, line = getNextLine(line); j < 300 && line && (line1 = getNextLine(line)); ++j, line = line1) { if ((n = (int)(line1 - line)) > 255) { n = 255; } strncpy(buf, line, n); buf[n] = '\0'; for (p = buf; *p == ' ' || *p == '\t'; ++p) ; if (!strncmp(p, "dup", 3)) { while (1) { p += 3; for (; *p == ' ' || *p == '\t'; ++p) ; code = 0; if (*p == '8' && p[1] == '#') { base = 8; p += 2; } else if (*p >= '0' && *p <= '9') { base = 10; } else { break; } for (; *p >= '0' && *p < '0' + base; ++p) { code = code * base + (*p - '0'); } for (; *p == ' ' || *p == '\t'; ++p) ; if (*p != '/') { break; } ++p; for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; if (code >= 0 && code < 256) { c = *p2; *p2 = '\0'; encoding[code] = copyString(p); *p2 = c; } for (p = p2; *p == ' ' || *p == '\t'; ++p) ; if (strncmp(p, "put", 3)) { break; } for (p += 3; *p == ' ' || *p == '\t'; ++p) ; if (strncmp(p, "dup", 3)) { break; } } } else { if (strtok(buf, " \t") && (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { break; } } } //~ check for getinterval/putinterval junk } else if (!gotMatrix && !strncmp(line, "/FontMatrix", 11)) { strncpy(buf, line + 11, 255); buf[255] = '\0'; if ((p = strchr(buf, '['))) { ++p; if ((p2 = strchr(p, ']'))) { *p2 = '\0'; for (j = 0; j < 6; ++j) { if ((p = strtok(j == 0 ? p : (char *)NULL, " \t\n\r"))) { fontMatrix[j] = atof(p); } else { break; } } } } gotMatrix = gTrue; } else { line = getNextLine(line); } } parsed = gTrue; } // Undo the PFB encoding, i.e., remove the PFB headers. void FoFiType1::undoPFB() { GBool ok; Guchar *file2; int pos1, pos2, type; Guint segLen; ok = gTrue; if (getU8(0, &ok) != 0x80 || !ok) { return; } file2 = (Guchar *)gmalloc(len); pos1 = pos2 = 0; while (getU8(pos1, &ok) == 0x80 && ok) { type = getU8(pos1 + 1, &ok); if (type < 1 || type > 2 || !ok) { break; } segLen = getU32LE(pos1 + 2, &ok); pos1 += 6; if (!ok || !checkRegion(pos1, segLen)) { break; } memcpy(file2 + pos2, file + pos1, segLen); pos1 += segLen; pos2 += segLen; } if (freeFileData) { gfree(fileData); } file = fileData = file2; freeFileData = gTrue; len = pos2; } xpdf-3.03/fofi/FoFiType1.h0000644000076400007640000000263211622305345014560 0ustar dereknderekn//======================================================================== // // FoFiType1.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FOFITYPE1_H #define FOFITYPE1_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "FoFiBase.h" //------------------------------------------------------------------------ // FoFiType1 //------------------------------------------------------------------------ class FoFiType1: public FoFiBase { public: // Create a FoFiType1 object from a memory buffer. static FoFiType1 *make(char *fileA, int lenA); // Create a FoFiType1 object from a file on disk. static FoFiType1 *load(char *fileName); virtual ~FoFiType1(); // Return the font name. char *getName(); // Return the encoding, as an array of 256 names (any of which may // be NULL). char **getEncoding(); // Return the font matrix as an array of six numbers. void getFontMatrix(double *mat); // Write a version of the Type 1 font file with a new encoding. void writeEncoded(const char **newEncoding, FoFiOutputFunc outputFunc, void *outputStream); private: FoFiType1(char *fileA, int lenA, GBool freeFileDataA); char *getNextLine(char *line); void parse(); void undoPFB(); char *name; char **encoding; double fontMatrix[6]; GBool parsed; }; #endif xpdf-3.03/fofi/FoFiType1C.h0000644000076400007640000001657311622305345014674 0ustar dereknderekn//======================================================================== // // FoFiType1C.h // // Copyright 1999-2003 Glyph & Cog, LLC // //======================================================================== #ifndef FOFITYPE1C_H #define FOFITYPE1C_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" #include "FoFiBase.h" class GString; //------------------------------------------------------------------------ struct Type1CIndex { int pos; // absolute position in file int len; // length (number of entries) int offSize; // offset size int startPos; // position of start of index data - 1 int endPos; // position one byte past end of the index }; struct Type1CIndexVal { int pos; // absolute position in file int len; // length, in bytes }; struct Type1CTopDict { int firstOp; int versionSID; int noticeSID; int copyrightSID; int fullNameSID; int familyNameSID; int weightSID; int isFixedPitch; double italicAngle; double underlinePosition; double underlineThickness; int paintType; int charstringType; double fontMatrix[6]; GBool hasFontMatrix; // CID fonts are allowed to put their // FontMatrix in the FD instead of the // top dict int uniqueID; double fontBBox[4]; double strokeWidth; int charsetOffset; int encodingOffset; int charStringsOffset; int privateSize; int privateOffset; // CIDFont entries int registrySID; int orderingSID; int supplement; int fdArrayOffset; int fdSelectOffset; }; #define type1CMaxBlueValues 14 #define type1CMaxOtherBlues 10 #define type1CMaxStemSnap 12 struct Type1CPrivateDict { double fontMatrix[6]; GBool hasFontMatrix; int blueValues[type1CMaxBlueValues]; int nBlueValues; int otherBlues[type1CMaxOtherBlues]; int nOtherBlues; int familyBlues[type1CMaxBlueValues]; int nFamilyBlues; int familyOtherBlues[type1CMaxOtherBlues]; int nFamilyOtherBlues; double blueScale; int blueShift; int blueFuzz; double stdHW; GBool hasStdHW; double stdVW; GBool hasStdVW; double stemSnapH[type1CMaxStemSnap]; int nStemSnapH; double stemSnapV[type1CMaxStemSnap]; int nStemSnapV; GBool forceBold; GBool hasForceBold; double forceBoldThreshold; int languageGroup; double expansionFactor; int initialRandomSeed; int subrsOffset; double defaultWidthX; GBool defaultWidthXFP; double nominalWidthX; GBool nominalWidthXFP; }; struct Type1COp { GBool isNum; // true -> number, false -> operator GBool isFP; // true -> floating point number, false -> int union { double num; // if num is true int op; // if num is false }; }; struct Type1CEexecBuf { FoFiOutputFunc outputFunc; void *outputStream; GBool ascii; // ASCII encoding? Gushort r1; // eexec encryption key int line; // number of eexec chars left on current line }; //------------------------------------------------------------------------ // FoFiType1C //------------------------------------------------------------------------ class FoFiType1C: public FoFiBase { public: // Create a FoFiType1C object from a memory buffer. static FoFiType1C *make(char *fileA, int lenA); // Create a FoFiType1C object from a file on disk. static FoFiType1C *load(char *fileName); virtual ~FoFiType1C(); // Return the font name. char *getName(); // Return the encoding, as an array of 256 names (any of which may // be NULL). This is only useful with 8-bit fonts. char **getEncoding(); // Get the glyph names. int getNumGlyphs() { return nGlyphs; } GString *getGlyphName(int gid); // Return the mapping from CIDs to GIDs, and return the number of // CIDs in *. This is only useful for CID fonts. int *getCIDToGIDMap(int *nCIDs); // Return the font matrix as an array of six numbers. void getFontMatrix(double *mat); // Convert to a Type 1 font, suitable for embedding in a PostScript // file. This is only useful with 8-bit fonts. If is // not NULL, it will be used in place of the encoding in the Type 1C // font. If is true the eexec section will be hex-encoded, // otherwise it will be left as binary data. If is non-NULL, // it will be used as the PostScript font name. void convertToType1(char *psName, const char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 CIDFont, suitable for embedding in a // PostScript file. will be used as the PostScript font // name. There are three cases for the CID-to-GID mapping: // (1) if is non-NULL, then it is the CID-to-GID mapping // (2) if is NULL and this is a CID CFF font, then the // font's internal CID-to-GID mapping is used // (3) is is NULL and this is an 8-bit CFF font, then // the identity CID-to-GID mapping is used void convertToCIDType0(char *psName, int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 (but non-CID) composite font, suitable for // embedding in a PostScript file. will be used as the // PostScript font name. There are three cases for the CID-to-GID // mapping: // (1) if is non-NULL, then it is the CID-to-GID mapping // (2) if is NULL and this is a CID CFF font, then the // font's internal CID-to-GID mapping is used // (3) is is NULL and this is an 8-bit CFF font, then // the identity CID-to-GID mapping is used void convertToType0(char *psName, int *codeMap, int nCodes, FoFiOutputFunc outputFunc, void *outputStream); private: FoFiType1C(char *fileA, int lenA, GBool freeFileDataA); void eexecCvtGlyph(Type1CEexecBuf *eb, const char *glyphName, int offset, int nBytes, Type1CIndex *subrIdx, Type1CPrivateDict *pDict); void cvtGlyph(int offset, int nBytes, GString *charBuf, Type1CIndex *subrIdx, Type1CPrivateDict *pDict, GBool top); void cvtGlyphWidth(GBool useOp, GString *charBuf, Type1CPrivateDict *pDict); void cvtNum(double x, GBool isFP, GString *charBuf); void eexecWrite(Type1CEexecBuf *eb, const char *s); void eexecWriteCharstring(Type1CEexecBuf *eb, Guchar *s, int n); void writePSString(char *s, FoFiOutputFunc outputFunc, void *outputStream); GBool parse(); void readTopDict(); void readFD(int offset, int length, Type1CPrivateDict *pDict); void readPrivateDict(int offset, int length, Type1CPrivateDict *pDict); void readFDSelect(); void buildEncoding(); GBool readCharset(); int getOp(int pos, GBool charstring, GBool *ok); int getDeltaIntArray(int *arr, int maxLen); int getDeltaFPArray(double *arr, int maxLen); void getIndex(int pos, Type1CIndex *idx, GBool *ok); void getIndexVal(Type1CIndex *idx, int i, Type1CIndexVal *val, GBool *ok); char *getString(int sid, char *buf, GBool *ok); GString *name; char **encoding; Type1CIndex nameIdx; Type1CIndex topDictIdx; Type1CIndex stringIdx; Type1CIndex gsubrIdx; Type1CIndex charStringsIdx; Type1CTopDict topDict; Type1CPrivateDict *privateDicts; int nGlyphs; int nFDs; Guchar *fdSelect; Gushort *charset; int gsubrBias; GBool parsedOk; Type1COp ops[49]; // operands and operator int nOps; // number of operands int nHints; // number of hints for the current glyph GBool firstOp; // true if we haven't hit the first op yet GBool openPath; // true if there is an unclosed path }; #endif xpdf-3.03/CHANGES0000644000076400007640000031636511622305344012723 0ustar dereknderekn0.2 (95-dec-12) --------------- First public release. 0.3 (96-jan-13) --------------- LZW patent workaround. Implemented inline images. Fixed (mostly) disjoint polygon fills. Added remote server stuff. Added page number on command line. Fixed problem with font encodings which caused character misalignment. Fixed inverted CCITT decoding and inverted image mask drawing. Now compiles under gcc 2.7.x (ignore those stupid 'unused parameter' warnings). Many minor bug fixes and optimizations. 0.4 (96-apr-24) --------------- Implemented DCT filter. Implemented PostScript output; wrote pdftops program. Implemented links. Implemented font rotation -- I was wrong: X11R6 servers *do* support font rotation (by specifying a matrix in place of a size). Added bindings for Home/End, Page Up/Down, arrow keys. Added initialZoom resource and -z option. Added geometry resource and -g option. Fixed image size off-by-one bug. Fixed bug where page content is reference to an array of streams. Cleaned up uninitialized variables which were causing random problems on various platforms. Manually skip whitespace before calling atoi() for startxref. Replaced calls to XrmCombineFileDatabase() with calls to XrmGetFileDatabase() and XrmMergeDatabases() so it will work under older versions of X. Fixed problem with reading multiple xref tables in updated PDF files. Check for encryption and print appropriate error message. Rudimentary dithering of images. Fixed bug in CCITTFax filter (pass mode followed by horizontal mode). Optimized drawImage() and drawImageMask(). Changed several things to ease porting: - changed '__inline' to 'inline' (to adhere to the ANSI standard) - surrounded interface/implementation pragmas with #ifdef _GNUC__ - got rid of empty array initializer lists - moved Operator type definition from Gfx.cc to Gfx.h - renamed String, uint, etc. - ability to uncompress to file (NO_POPEN and USE_GZIP flags) - added definitions of XK_Page_Up/Down and XPointer for old versions of X For VMS port: - use correct Xdefaults name for VMS, get rid of ltkGetHomeDir() - added '#include ' before all X includes - renamed files with multiple periods in their names Fixed window resizing infinite oscillation bug. Fixed problem with string-type (as opposed to stream-type) indexed color space lookup tables (which are used in inline images). If an X font is not found, try smaller and then larger sizes (this is useful for old or broken X servers which can't scale bitmap fonts). Added -rgb (color cube size) option. Various minor bug fixes. 0.5 (96-may-23) --------------- Fixed bug in LTKWindow which broke the remote server mode. Fixed PostScript output: - doesn't seg fault if file is unwritable. - incorrect DSC comment - need colon in '%%Page:'. - use 'imagemask' command for masks. - output filters in the correct order. - Stream::isBinary() checks the next-to-bottom, not top, stream. - if page width > height, rotate it 90 degrees. - if page is larger than paper size, scale it down. Set default MediaBox to 8.5" x 11" to deal with non-compliant PDF files which don't specify a MediaBox. Added DEBUG_MEM stuff in gmem.c and gmempp.cc. Fixed memory leaks: - LTKWindow didn't delete the LTKBox. - LinkAction needs a virtual destructor. Use $(RANLIB) variable in goo/Makefile and ltk/Makefile. Allocate image data after calling XCreateImage, using image->bytes_per_line -- works in 24-bit mode now. DCTStream rounds width of rowBuf lines up to the next multiple of mcuWidth, so last MCU doesn't run off end of buffer. Increase size of block (from 255 to 1024 bytes) read at end of file to search for 'startxref'. Skip past garbage at start of file, look for '%PDF'. Moved more compiler options out of Makefiles into Makefile.config. Top-level Makefile uses '$(MAKE)' instead of 'make' for making subdirectories. Space/PageDown/Next and Backspace/PageUp/Previous now moves to next/previous page if already scrolled to bottom/top of current page. 0.5a (96-jul-09) ---------------- [not a public release] For PDF 1.2 (a.k.a. Amber, a.k.a. Acrobat 3) support: - look for trailer after first xref instead of at end of file. Deal with font subsets by converting character names of the form 'Cnnnn' to the appropriate character from the standard encoding. Extract encoding from embedded Type 1 fonts. Kludge to fill one-pixel thick polygons. Changed X font encoding to use endash for hyphen (gets rid of too-long hyphens). Handle Resources key in Pages dictionaries (needed for pstoedit output). Fix comment handling in Parser (needed for pstoedit output). Move Bezier curve conversion from GfxState to XOutputDev; look at flatness parameter in GfxState. Change all of the path functions in XOutputDev (stroke, fill, clip) to use the same path transformation/conversion function. Rewrote PostScript output driver as a subclass of OutputDev; removed duplicated code (ps_ functions) from Gfx. Fixed bug in xref code with small (< 1024 bytes) PDF files. Implemented BX/EX operators. Added PDFDoc class. 0.6 (96-nov-12) --------------- Add support for PostScript output to stdout (-) and to a command (|lpr); added -ps option and psFile resource. Decryption is implemented but not included in the distribution due to legal restrictions: the decryption algorithm is a trade secret of RSA, Inc., and the U.S.A. still has bogus export controls on cryptography software. Added .xpdfrc config file: - Added fontmap parameter: user can map PDF font names to X fonts. - Added fontpath parameter: search for Type 1 font if encoding is not in PDF file. Incremental display: display is updated after every 200 commands. Added forward and backward by-10-page buttons. Links: - Implement links with "Launch" actions that point to PDF files. - Draw borders around links. - Handle links with named destinations. - GoToR links specify a page number instead of a page reference. Optimizations: - Rewrote Stream to use buffering, and added lookChar() functions; rewrote Lexer to take advantage of this. - Use hash tables for name->code mapping in font encodings. - Made XOutputDev::doCurve() iterative, changed /2 to *0.5, and changed the flatness test. Added file name to window title. Implemented RunLength filter. Implemented forms. Convert ObjType to an enum. Changed isDict("Pages") to isDict() (in Catalog.cc) to deal with incorrect PDF files. Changed color selection so that very pale colors don't map to white. Fixed bug in CCITTFax filter (multiple make-up codes). In GString::clear(): need to set length to 0 before calling resize(). Base initial window size on first displayed page, not page 1; deal correctly with rotated pages. Added ltkGetIntResource() and LTKApp::getIntResource(). PostScript output fixes: - Escape backslashes in strings. - When doing ASCII85 encoding, keep both chars of EOF marker ('~>') on same line. - Add extra line '%-EOD-' after image data streams; call wrapper functions for image and imagemask which look for this line -- this should fix the 'too much data in stream' bug. - Font tags can be reused for different fonts on different pages -- so use font object reference (number/generation) instead. Initialize character widths to zero (this caused crashes on OSF/1). Handle image masks which go outside of pixmap. Makefile.config changes: - Remove -o in C++ compile rule. - Add $(AR) variable. Code which read char widths from font dictionary read all but the last width. Add 'return 0;' to main() in xpdf and pdftops. Allow fonts to use StandardEncoding. Convert man pages to VMS help files. 0.7 (97-may-28) --------------- Implemented FlateDecode filter (for PDF 1.2). Basic xref table reconstruction for damaged files New pdftotext program converts PDF to plain text. Implemented menus in LTK; added a menu to xpdf. Added open and save functions; allow xpdf to start without any PDF file. Implemented text find. Implemented text select/copy. Change mouse cursor when it's over a link. Embed Type 1 fonts in PostScript output. Moved rotate functions to menu; added quit to menu. Fixed stroke color bug in PostScript output (was using fill color instead of stroke color; this sometimes caused lines to be missing (white) in PostScript output). Support Launch-type links -- pops up a dialog before executing anything. Expects the A (action) dictionary to contain a Unix dictionary with F (file) and P (paremeter) keys just like the Win dictionary. A moveto op all by itself should just be discarded, instead of generating a subpath with one point (this was causing seg faults). Balanced parentheses in strings don't need to be escaped. Tj operator in PostScript prolog didn't check for zero when dividing by length of string. Implemented selection in LTK; TextIn widgets support dragging/copy/ paste. Handle font subsets that use hex character codes. Added icon pixmap; added the XPMLIB and NO_XPM variables to Makefile.config. Fixed subtle bug in use of horizontal scaling parameter (it affects only the width of drawn characters, not positioning done in text space). Memory testing (with DEBUG_MEM): - gmalloc now fills memory blocks with garbage to catch unitialized fields. - gfree fills memory blocks with garbage to catch uses of freed blocks. Handle image masks which go off the pixmap on the top and/or left. Fixed inline functions which had two return statements (to make the HP, SCO, and other cfront-based compilers happy). Fixed bug which caused seg faults when following a link to a different file (info in LinkGoto object was used after link was deleted by loadFile). If page content is an array of streams, the streams are concatenated; objects and commands can span multiple streams. If file open fails, try lower-casing and upper-casing the file name. Commands should end when lexer sees a '/' character. GString::append(char *, int) was broken. Changed LTKScrollingCanvas redraw to be more efficient: copy as much as possible from window before copying from off-screen pixmap. Ignore gs (set extended graphics state) operator. Handle colorspaces (CalGray/RGB are treated as DeviceGray/RGB; the weird colorspaces are not yet implemented). Named destinations (for links) can be strings as well as names; deal with the names tree in the catalog. Clip to the page CropBox. Added '-q' to gzip options (to suppress warnings, in case user has -v in GZIP env var). Added 'include Makefile.config' to top-level Makefile. Added INSTALL variable to Makefile.config; used in top-level Makefile. Always initialize LinkDest left/bottom/top/right/zoom fields (bogus floating point values were causing crashes on Alpha). Added Makefile.config options for Digital Unix (DEC compilers), HP-UX (HP compilers), SCO Unix, and Evans & Sutherland ES/OS. Added flag to set stream mode in fopen call for VMS. Rewrote Link module. Pages with no contents shouldn't cause an error message. In PostScript output: pdfImM needs to set fill color before doing imagemask. If font doesn't specify character widths, use widths from built-in font, based on font flags. Fixed LTK scrollbar to delay before repeating and to control the period between repeats. Removed window/widget copy() methods (they were untested and unused). Unknown filter types produce a single error message instead of a stream of errors. Added a dummy target in top-level Makefile so making individual executables (e.g., 'make pdftops') should now work. Added optional xpdf-flip.ltk with buttons on right side instead of bottom of window. 0.7a (98-feb-22) ---------------- Moved find command from menu to toolbar button ('f' key still works). Support TrueColor visuals. Added a -cmap option and a installCmap resource to install a private colormap. Mouse button 2 pans the window. Selecting a URI link now executes a configurable command (from the urlCommand resource). Added a "link info" display which shows the URL or file for the link under the mouse. Don't draw (or convert to PostScript) text drawn in render modes 3 and 7 -- this is invisible text, used by Acrobat Capture; this text is still passed to the TextPage object so that selection works. Recognize (and quietly ignore) marked content operators (BMC, BDC, EMC, MP, DP). Recognize new color-setting operators (scn, SCN). Added A4_PAPER option. Embed external Type 1 font files (this currently only works with PFA files). Added "-level1" option (in xpdf and pdftops) to generate Level 1 PostScript. Setup autoconf -- replaced Makefile.config. Added SELECT_TAKES_INT flag, and use configure to autodetect (for HP-UX). Fixed appendToPath() to behave reasonably when appending ".." to root directory. Fixed array size in FlateStream::compHuffmanCodes() (was causing xpdf to crash under OSF/1). ASCII85Stream, ASCIIHexStream, and DCTStream didn't check for EOF and could run past the end of the stream in damaged files. Handle hex escapes (#xx) in names. Still allow the name /# for backward-compatibility. Check for NULL characters in encoding array in GfxFont.cc (was calling strcmp() with NULL which crashed under Solaris). PageAttrs::PageAttrs() didn't initialize crop box boundaries. Changed uses of lookup() to lookupNF() in XRef.cc. Fixed type checking of operators which take a variable number of args. Gfx::buildImageStream() doesn't need to check for parser (since I got rid of the bogus array-of-command thing). XOutputFont matches on font reference instead of font tag (similar to PSOutputDev fix). Fixed bug in position calculation for multi-char substitutions in XOutputDev. Cleaned up local variables which hid class variables. Optimized variable length decoding in CCITTFaxStream. Set link border width to zero if Border dictionary entry is missing. Throw away zero-length strings in TextOutputDev -- they don't have valid xMin/xMax values. Swapped order of XLIBS and XPMLIB in xpdf/Makefile. Deleted 'LTKApp::' in function declaration in LTKApp.h. Changed '(XKeyEvent *)&event' to '&event.xkey' in LTKApp.cc. Check that the link rectangle coordinates are in the correct order, and swap if necessary. TextOutputDev didn't set text to NULL, which caused pdftotext to segfault if it couldn't open it's output file. Fixed a hash table search bug in GfxFontEncoding::getCharCode(). Cleaned up colorspace code: rewrote GfxColorSpace and added GfxImageColorMap; cleaned up PSOutputDev::doImage. Handle named colorspaces in images. Correctly set the default color after a colorspace change. Old setcolor operators now set the colorspace. Fixed bug with uncompressed blocks in FlateStream. Fixed bug with fixed Huffman code table in FlateStream. Added hash table of X windows (for LTKWindow and LTKWidget) to LTKApp and replaced calls to XQueryTree with hash table searches -- this avoids a roundtrip to the server for each event and also fixes the problem where XQueryTree crashed if the window no longer existed (with leftover events from a destroyed window). (Thanks to Yair Lenga for the suggestion.) Create a new GC for selection -- xor black and white (instead of LTK foreground and background). Fixed crash with blank lines in .xpdfrc. Allow spaces in font descriptors in fontmap lines in .xpdfrc. Check for bogus object number in XRef::fetch(). Use MacRomanEncoding for TrueType fonts that don't specify an encoding. Certain PDF generators apparently don't include FontDescriptors for Arial, TimesNewRoman, and CourierNew -- set GfxFont flags appropriately. Fixed a bug in width guessing in GfxFont -- sans serif and serif were swapped. Rewrote XRef::readXRef() to avoid using a parser to read the xref entries. Added NO_TEXT_SELECT option. Ignore APPn/COM/etc. markers in DCT streams. Replaced select() with XMultiplexInput() in LTKApp.cc for VMS. Handle WM_DELETE_WINDOW protocol -- if you ask the window manager to delete the xpdf window, xpdf will exit cleanly; other windows/dialogs are simply closed. Optimized DCT decoder; switched to integer arithmetic. The "/Type /Annots" field in an annotation dictionary is optional. Check for null nameTree in Catalog::findDest(). In XOutputDev, search user font map before default font map. Added "normal" SETWIDTH parameter to all font descriptors in XOutputDev (some systems have a narrow-width Helvetica font). Added FOPEN_READ_BIN and FOPEN_WRITE_BIN to support Win32. Added a hack which allows better font substitution for some Type 3 fonts. Also allow character names of the form /nn and /nnn. Added and to LTKApp.cc (needed by AIX and IRIX for bzero() declaration for FD_ZERO). 0.80 (98-nov-27) ---------------- Support for some Japanese fonts (Type 0 fonts using the Adobe-Japan1-2 character collection, horizontal only). Added pdfinfo application. Added pdftopbm application. Added pdfimages application. Added -papercolor option and .paperColor resource. Fixed divide-by-zero problem in XOutputDev Type 3 font matrix kludge. Font subset char names can be 'Bxx' as well as 'Cxx' and 'Gxx'. Fixed bug in color space conversion in DCTStream filter (YCC->RGB was correct, YCCK->CMYK was broken). Added XRef::getDocInfo() and PDFDoc::getDocInfo() to support pdfinfo. Optimized GfxImageColorMap. Lexer::getStream(), getPos(), and setPos() check for null stream. Decryption code now does strings as well as streams. ASCII85 decoder rounds short tuples up instead of down. CropBox and MediaBox can be non-integers. PostScript output: - Use a rectangle operator. - Call setpagedevice with page size. - Insert %%PageOrientation comments. - Add paper size flags (-paperw and -paperh) to xpdf and pdftops. - If HAVE_POPEN is not defined, and user tries to print to '|...', the PSOutputDev destructor tried to write to the PS file. - Added support for forms (pdftops -form). Removed error messages for empty paths in stroke, fill, etc. operators. Don't allow flatnesses less than 1 in XOutputDev (this speeds up rendering a little bit when there are lots of tiny curves). Moved the font subset character name guessing from GfxFont to XOutputDev and TextOutputDev - now these files print correctly. Cast argument to XFree() to XPointer; add XPointer definition where necessary (portability fixes). Various minor VMS fixes. Changes to configure script and Makefiles: - Print a warning if X is missing. - Use C++ when checking select() argument type (HP-UX). - Use 0 instead of NULL when checking select(). - Default to gcc instead of c++. - Get rid of AC_C_INLINE -- this is meant for C, not C++. - Changed -USE_GZIP to -DUSE_GZIP. - Added ability to compile ouside of the source tree. - Added .cc.o rule to {goo,ltk,xpdf}/Makefile.in. - Added @LIBS@ to XLIBS in xpdf/Makefile.in. - In top-level Makefile.in: added '-' to clean commands; added distclean rule. - Create install directories. - Use INSTALL_DATA (instead of INSTALL) for man pages. - Changed xpdf-ltk.h rule to avoid leaving an empty file when ltkbuild fails. - Change things so that by default, ltkbuild is not built and xpdf-ltk.h is not rebuilt. - Use AM_PROG_CC_STDC to add compiler flags for ANSI C. - Modify autoconf's builtin macros to check for xlC. - Use Steve Robbins' smr_CHECK_LIB to test for pixmap library (Xpm) -- this should fix the problems on systems that have the library but not the include file. - Added better test for sys/select.h, sys/bsdtypes.h, strings.h, bstring.h. - New VMS make scripts from Martin P.J. Zinser. - Moved dependences into Makefile.in -- this gets rid of problems with 'cc -MM' (which is gcc-specific) and 'include Makefile.dep' (which isn't supported by all make implementations). Also changed all non-system include files to '#include "..."' (from '<...>'). Tweaked the TextOutputDev heuristics slightly. Modify Gfx to use a stack of resources -- this is necessary for Form XObjects, which can define their own local resources; also modified PSOutputDev to dump fonts used by forms. Look for excessively large MediaBox (compared to CropBox) and shrink it to CropBox. Minor fix to scrolling when dragging a selection. Various patches for pdftex and Win32 support. Deal with Separation colorspaces by using their alternate colorspace entry. Added PBMOutputDev for pdftopbm application. Added ImageOutputDev for pdfimages application. Separated XOutputDev into LTKOutputDev + XOutputDev. Added support for 1-D and mixed 1-D/2-D (Group 3) decoding to CCITTDecode filter. Added resetImage(), getImagePixel(), and skipImageLine() to Stream class; used these in XOutputDev, PSOutputDev, and ImageOutputDev. Implemented predictor for LZW and Flate filters. In pdfImM1 in PSOutputDev prolog: div should be idiv. Changed output from printUsage() function in parseargs to look nicer. 0.90 (99-aug-02) ---------------- Added Type 1/1C font rendering, using t1lib. Added "backward" and "forward" buttons. Added fit-page and fit-page-width zoom factors; replaced zoom-in and zoom-out buttons with a zoom popup menu. Type 1C fonts are converted to Type 1 and embedded in PostScript. Support vertical Japanese text. Added Japanese text support (EUC-JP) to pdftotext. Bumped PDF version to 1.3. Added stub functions for ri and sh operators. (But there are still some missing 1.3 features.) Added -raw option to pdftotext. Minor changes to allow compiling under MS Visual C++ 5.0. Top-level makefile: changed 'mkdir -p' to '-mkdir -p'. Configure script: added X_CFLAGS to smr_CHECK_LIB(Xpm). Added Xpm_CFLAGS to xpdf/Makefile.in (this is needed to get the -I for the xpm includes). Rewrote code that handles font encodings; added support for Type 1C fonts. In the setpagedevice dictionary in PostScript output - added a /Policies entry which tells the PS interpreter to scale the page to fit the available paper. Changed PageUp behavior slightly: move to bottom (instead of top) of previous page. TextPage used character's dx (width + char space) instead of just its width. Read base URI from document Catalog (for URI-type links). Minor change to configure script to avoid using 'unset'. Fixed bugs in CropBox inheritance. Fixed a bug in resource stack handling for form objects. Display forms even if they have a missing/incorrect FormType. Fixed a bug in stream predictors -- the predictor parameters (width, comps, bits) don't need to match the actual image parameters. Completely rearranged the predictor code. Fixed PostScript output to correctly handle stream predictors. Don't segfault on empty (zero-page) documents. Added the xpdf.viKeys feature. Added the ffi and ffl ligatures to XOutputDev and TextOutputDev. Pdftotext and pdfimages now check okToCopy(). Added a '-q' flag to all programs (except pdfinfo) to suppress messages and errors. Deal with DeviceN colorspaces by using their alternate colorspace entry. Change PostScript output so setpagedevice is only called once, at the very beginning of the document (to avoid problems on duplex printers). Changes to configure script and makefiles for DOS/DJGPP. FontEncoding::getCharCode() looked for (code>0) instead of (code>=0). Added keypad arrow keys, etc. to xpdf. Minor changes to gfile.{h,cpp} () to compile under VC++. Fixed CCITTFaxStream to correctly handle all parameters. Modifications to gfile.{h,cc} for Acorn. Some minor changes for OS/2. Added 'SHELL = /bin/sh' to Makefiles. Compare file version to pdfVersionNum+0.0001 to avoid floating point precision problems. Added LDFLAGS to Makefiles. Removed strip entirely from configure and Makefiles. Fixed a bug in choosing the correct DCTStream color transform. 0.91 (2000-aug-14) ------------------ Added TrueType font rendering, using FreeType. Support for Chinese fonts (Type 0 fonts using the Adobe-GB1-2 character collection). Decryption code is included with the main distribution (now that the US export regulations are a little bit less irrational). Added (very basic) support for generating PostScript with Japanese fonts -- only tested with ghostscript so far. Added support for generating EPS files (pdftops -eps). Much-improved image filtering in xpdf (for downsampling and for transforms other than 0/90/180/270-degree rotations). Implemented a basic full-screen (presentation) mode (xpdf -fullscreen). (There is currently no way to switch between window and full-screen modes on the fly -- this will be fixed in a later release.) Added "reload" menu item. Do a better job with anti-aliased Type 1 fonts on non-white backgrounds. Handle Lab color spaces. Handle non-null user passwords. Avoid security hole with tmpnam()/fopen() -- added openTempFile() in goo/gfile.cc. [Thanks to Joseph S. Myers for pointing this out.] Filter out quote marks (' and ") in URLs before running urlCommand to avoid a potential security hole. [Thanks to Frank Doepper for pointing this out.] Fixed TrueColor detection to look at the complete list of available visuals, not just the default visual. In gfile.h, changed NAMLEN(dirent) macro to NAMLEN(d). Removed copyright character from start-up banners. In the open and save dialogs, if the open/save button is pressed with no file name, the dialog is not canceled. Added Xpm_CFLAGS to ltk/Makefile. XOutputDev::updateLineAttrs was using dashLength before it was defined. In top-level Makefile.in, use INSTALL_PROGRAM instead of INSTALL. In man page, recommend -q instead of -err in .mailcap. Changes for GNOME / Bonobo support: - Separated Stream classes into BaseStream and FilterStream trees. - Got rid of all FileStream-specific stuff. - Added a PDFDoc constructor that takes a BaseStream* instead of a file name. Allow newlines inside strings (Photoshop does this). Don't require whitespace between tokens in consecutive content streams (for pages that specify an array of streams). Look at MissingWidth when constructing font character widths array. Fixed a bug that caused incorrect PostScript output for images that use 8-bit indexed color spaces with < 256 colors in the palette. Handle case where embedded font file is bad (this was seg faulting). Minor changes for Windows/pdftex. Work around a bug in PDF files from the IBM patent server. Fixed bugs in PostScript form generation: use pdfStartPage instead of pdfSetup; problem with inline images. Minor bug fix in FlateStream::loadFixedCodes(). Added %%DocumentMedia and %%PageMedia comments to the PostScript so that gsview (a Windows frontend for ghostscript) gets the right paper size. Draw AcroForm fields that have appearance annotations. Bounds check gray, CMYK, and RGB values (in GfxColor). Moved the link border drawing code into Page (from PDFDoc). Minor modifications for pdftohtml. PSOutputDev: use the Type 3 font scaling kludge from XOutputDev. Separation color spaces were handled incorrectly in images. Fixed a bug with form bounding boxes. Modified the t1lib support -- replace libt1x code with my own code. Type 1 and TrueType fonts are now handled similarly, and clipping works on Type 1 fonts. Don't print copyright banner (xpdf); add -v switch to get copyright and version info (all apps); get rid of -err switch (xpdf). Automatically reload the PDF file if it has been changed, i.e., if the modification time is different. Fixed a memory (malloc size) bug in CCITTFaxStream. Fixed two bugs in FontEncoding::hash() -- handle zero-length character names (which were found in a (buggy?) PDF file), and handle character names with high-bit-set characters (use unsigned ints). Added PDFDoc::isLinearized() and corresponding code in pdfinfo.cc. Handle files with an incorrect page count in the Pages dictionary (FOP, from the Apache project produces a page count of 0). Handle TrueType equivalents to the Base14 fonts (Arial, TimesNewRoman, CourierNew) -- Adobe's tools use these names without embedding the fonts. Tweaked the Type 3 font sizing kludge. Changed pdfimages (ImageOutputDev) so it doesn't output JPEG files for 4-component color spaces, since these seem to confuse most image viewers. Added support for generating OPI comments (pdftops -opi). In XOutputDev::drawImage() and drawImageMask(), check for images that are completely off-page. Use the provided alternate or a default (DeviceGray/RGB/CMYK) color space for ICCBased color spaces. Incorporated MacOS-specific code from Leonard Rosenthol. Configure script switches to C++ for the strings.h/bstring.h test. Gfx::opRestore() calls clearPath() to handle (apparently) buggy PDF files produced by FreeHand. The /Type field in most dictionaries is optional (PDF 1.3 change). Move printCommands variable definition into Gfx.cc. If page is smaller than paper, center the PostScript output. Fix a minor bug in the SELECT_TAKES_INT detection in the configure script. TextOutputDev filters out control characters. Changed enough occurrences of 'char *' to 'const char *' to keep gcc 2.95 from barfing. Support for Latin-2 and Latin-5 in pdftotext (however, this will only work if the PDF file contains correct font encodings, which seems to be rare). TextOutputDev converts "eightoldstyle" to "eight", etc. Don't use the return value from sprintf() -- most systems return the length, but some return the string. Minor fixes for SunOS 4. Configure script looks for both select() and fd_set in sys/select.h. Configure script checks for gethostbyname() in -lbsd (for LynxOS). Fix missing closepath bug in PostScript output. Change PostScript portrait/landscape mode selection so it only uses landscape if the page width is greater than the paper width. Tweaked the VMS code in makePathAbsolute(). 0.91a (2000-oct-11) ------------------- Implemented separable CMYK PostScript output (the -level1sep switch to pdftops). Implemented Pattern color spaces with tiling patterns (polygon fills only). Implemented Stamp annotations. Implemented Named link actions. Fixed a really dumb bug in the TrueColor code in SFont (which affects both Type 1 and TrueType font rendering on 16-bit displays). Rewrote the GfxColorSpace / GfxColor code. Switched from djgppcfg to dj_make.bat (from Michael Richmond). Bug in the Type 1 encoding parser -- couldn't handle lines of the form 'dup NNN/name put' (with no space between the code and the name). Fixed the mkstemp() test in configure.in -- switched from AC_TRY_COMPILE to AC_TRY_LINK and added . Added DESTDIR to top-level Makefile.in. Fixed an incorrect OPI comment in PSOutputDev. Minor tweak to the CCITTFax code to avoid writing past the end of an array on an invalid data stream. Xpdf crashed if the user selected 'reload' when no document was loaded. Look for character names of the form "xx" (two hex digits with no leading alphabetic char) and 'cNNN' (decimal digits with a leading alphabetic char that happens to be a hex digit). FlateStream didn't correctly handle zero-length streams. Xref reconstruction didn't handle the case where the opening "<<" immediately followed "trailer" with no intervening whitespace. Fix the %%DocumentSuppliedResources comment in EPS output. Scale annotations to fit their rectangles. Added Stream::close() to handle cases (e.g., patterns) where a Stream object is used multiple times before it is deleted. Added the topLevel arg to Gfx::go() so it doesn't call out->dump() for every pattern element (and form). Rearranged the GfxResources class. Clean up white space handling in Lexer. Make the dpi parameter to PDFDoc::displayPage etc. a double - this avoids margin gaps with fit-page and fit-width. Fix a rounding problem in xpdf.cc that was causing the window to sometimes be one pixel too small. Fixed a minor bug in dealing with Base-14 TrueType font names. Fixed Lab -> RGB color space conversion. Added support for opacity values (from PDF 1.4) to GfxState and OutputDev. [Thanks to Leonard Rosenthol.] Implemented type 2 functions; rearranged the Function class hierarchy. 0.91b (2000-oct-29) ------------------- Print a warning about Type 3 fonts (XOutputDev, PSOutputDev). Added the scroll lock behavior to 'n' and 'p' keys in xpdf. Change FileStream buffer size to a #define'd constant. Renamed Pattern to GfxPattern to avoid clashes with Windows and MacOS types. Added CNS (Big5) Chinese font support (CHINESE_CNS_SUPPORT); renamed CHINESE_SUPPORT to CHINESE_GB_SUPPORT. 0.91c (2000-nov-19) ------------------- Fix an endianness problem in the Type 1 font code which resulted in an incorrect display with "-t1lib plain" on big-endian systems. CCITTFax stream decoder will skip over extra zero bits at end of line, even if EncodedByteAlign flag wasn't set. Added Big5 support to pdftotext (with CHINESE_CNS_SUPPORT enabled). Fixed a typo in the CNS/Big5 encoding translation table. Change the form code in PSOutputDev to store images in arrays of strings. The xref reconstruction (for damaged files) now also looks for 'endstream' tags, and the parser uses this information when setting up stream objects. In pdfinfo, convert Unicode chars in the 00xx range into 8-bit chars; print a warning if there are any other Unicode chars. 0.92 (2000-dec-03) ------------------ Fixed %%BeginResource comment (for xpdf procset) in PostScript output. Added "-title" switch and "xpdf.title" resource to set the window title. Check for in addition to . Upgraded the configure script to smr_macros 0.2.4 - this should fix a bug where configure wasn't correctly finding t1lib. 0.92a (2000-dec-17) ------------------- Added 'extern "C" { ... }' in various places for ANSI C++ compliance. Tweaked the code that figures out DPI for fit-to-page and fit-to-width modes. Fixed the image transformation code in XOutputDev -- no more missing lines. Implemented color key image masking in XOutputDev. 0.92b (2001-jan-07) ------------------- Fixed a bug in the error-checking code in the Separation/DeviceN color space parsing functions. [Thanks to Lidia Mirkin.] Added wheel mouse support (mouse buttons 4 and 5). [Thanks to Thorsten Schreiner.] Added preliminary support for FreeType 2 (disabled by default). 0.92c (2001-jun-04) ------------------- Fixed a bug in the new image transformation code. Look for character names of the form "", instead of looking for names beginning with a few specific letters. T1FontFile::T1FontFile wasn't initializing vars, and ~T1FontFile wasn't checking before calling T1_DeleteFont -- this caused crashes if it tried to open a nonexistent font file. Catalog::Catalog didn't set baseURI to NULL early enough. Tweak the check for strings.h in the configure script. Yet another fix for the image rotation code in XOutputDev -- off-by-one problem when upsampling. Handle Type 1/1C encodings when using FreeType 2. Allow FreeType2 to render user-supplied Type 1 base fonts. Opening a new file from full-screen mode tried to scroll. Fixed a bug in GfxFont constructor (missing check for NULL base font name). Don't crash if a Type 1 font's FontBBox is non-integer. Pdfinfo prints page size. Tweak for the alpha hack in T1Font/TTFont: sample the middle pixel instead of the top-left pixel. Automatically activate the text input widget in the find window. Changed a Japanese char code mapping in XOutputDev and TextOutputDev: period was being incorrectly mapped to small circle (end-of-sentence character). Add the 0/+/-/z/w key bindings to control the zoom setting. Fixed ImageOutputDev (pdfimages) to correctly handle inline image masks. Extract ascent/descent info from font descriptor. 0.92d (2001-jun-26) ------------------- Embed TrueType fonts in PostScript output. (Added a "-noembtt" flag to pdftops.) Extract encoding from TrueType fonts. Moved Function classes to a separate file (Function.h/cc). Implemented multi-dimensional sampled Functions. Implemented Type 4 (PostScript calculator) Functions. For Type 0 fonts, FontDescriptor is in descendant font, not parent. [Thanks to Lidia Mirkin.] Added the "-htmlmeta" option to pdftotext. In TextOutputDev, when computing the number of blank lines to insert, do a sanity check on the result. If both FlateDecode and some other filter (e.g., DCTDecode) were applied to an image stream, getPSFilter() crashed instead of just returning NULL. Handle the /Identity function. 0.92e (2001-aug-23) ------------------- Widths in font dict should override built-in font widths. Changed "rotate left/right" menu items to "rotate clockwise/counterclockwise". The link parsing code choked if the Border array was incorrect (too short). Modified PSOutputDev to output CMYK for fill/stroke colors. 0.93 (2001-oct-25) ------------------ Implement PDF 1.4 (128-bit) decryption. Bump supported PDF version number to 1.4. Text output for Simplified Chinese. [Thanks to Cheung Siu Fai.] Read an app-defaults file for Xpdf. Read a system-wide config file (/etc/xpdfrc) if ~/.xpdfrc doesn't exist. Accept and verify owner password; if correct, allow all actions. Added a "-level2sep" option to pdftops to generate Level 2 separable PostScript. The PostScript separation convention operators are used to handle custom (spot) colors. [Thanks to Thomas Freitag for help on this.] Add support for FreeType 2 to the configure script. Warning: this requires FT 2.0.5 or newer. Fixed the bounding rectangle overlap test in the disconnected subpath fill hack in XOutputDev. Stupid typo in font name table in PSOutputDev. Changing the zoom setting with a keyboard shortcut didn't update the displayed setting. Modified the mouse wheel support and added the second wheel (mouse buttons 6 and 7). [Thanks to Michal Pasternak.] Character and word spacing is affected by horizontal scaling (display and PS output). [Thanks to Eddy Ng.] Rotation specified by the text matrix, character spacing, and horizontal scaling interacted incorrectly (display and PS output). Some broken Type 1/1C fonts have a zero BBox -- kludge around this by assuming a largeish BBox. Handle PDF files with an incorrect (too small) xref table size. Allow "-?" and "--help" as aliases for "-h" (all apps). Correctly handle unescaped parens in strings in Lexer. Fixed a bug in LTK where a menu got posted multiple times if you right clicked while a page was being rendered. Removed a comma inside a string in configure.in. Kludge around broken PDF files that use char 32 but encode it as .notdef instead of space. Clean up various compiler warnings: use constructor args like "fooA" if there is a field named "foo". Everything now compiles cleanly under gcc 2.91.66, 2.95.2, and 3.0.1. Page objects now read all of the page rectangles (MediaBox, CropBox, BleedBox, TrimBox, ArtBox), as requested by the pdfTeX folks. Added a new PDFRectangle struct to hold these. Use XOutputDev's Type 3 font size hack in TextOutputDev too, so it does a little better job of extracting text in Type 3 fonts. Modify pdfimages to write one-bit images as PBM files. Work around a bug in cygwin's implementation of fseek. 0.93a (2001-nov-21) ------------------- Implemented the sh (shaded fill) operator for the axial shading type. Minor fixes to avoid compiler warnings. Cleaned up global variables -- moved many into instance vars and function args. Minor fixes for OS/2. Fix the system config file path for VMS. Fix an uninitialized var in XOutputDev that caused crashes on Alphas. Don't incrementally update the display in full-screen mode. For Type 1/1C fonts, use the FontBBox from the PDF FontDescriptor (instead of the one in the font file) if present -- this avoids problems with fonts that have non-standard FontMatrixes. Add the Euro character to WinAnsiEncoding. Track the bounding box of the clip region to make rendering patterns more efficient. Fix openTempFile() for Win32. 0.93b (2001-dec-11) ------------------- Added a duplex option to PSOutputDev and a -duplex switch to pdftops. Added XRef::PDFgetDocInfoNF() for pdftex project. Updated the VMS build script. 0.93c (2001-dec-12) ------------------- Completely rewrote the code that handles font encodings: - everything is Unicode-based - 16-bit fonts are handled much more cleanly - text output encoding can be set more flexibly New .xpdfrc config files. 1.00 (2002-feb-01) ------------------ More work on the font encoding rewrite: - use the ToUnicode font dict entry - pdfinfo and pdftotext (with '-htmlmeta') convert info strings to the selected text encoding Added key bindings for forward ('v') and backward ('b'). Added the pdffonts program which lists the fonts used in a PDF file. Fixed several problems in the TrueType font embedding code (for PostScript output). Accept named destination on command line. Added several new items to pdfinfo: file size, PDF version, tagged (yes or no), XML metadata (with the -meta option). Pdftops didn't get the portrait/landscape setting correct for PDF files with rotated pages. The TrueTypeFontFile class (including the Type 42 converter) now understands cmap format 6. Improved the "about" window -- mention the GPL, add a list of key bindings. Added Zcaron and zcaron characters to WinAnsiEncoding. The '0' keyboard shortcut didn't update the zoom popup menu. Handle the complete list of alternate names for the Base14 fonts. Fixed substitute font scaling in XOutputDev - scale only the width, not the height. Implemented stitching (type 3) functions. Handle the case of moveto/closepath/clip, which defines an empty clipping region. Move dependences into separate Makefile.dep files; get rid of the distdepend target. Move all of the configure-script-generated -D options out of the Makefiles and into a top-level .h file (aconf.h). Cleaned up the FreeType 1/2 detection code in the configure script. Pdfinfo prints dates in a more readable format. Fixed a bug in the Paeth image predictor. Handle annotations with multiple states. Another workaround for buggy X servers: clip points that are way out of bounds. Added libpaper support (for Debian). Generate PostScript DSC resource comments for PS (not just EPS) files. The save and restore (q/Q) operators shouldn't save/restore the path. Performance optimization: disable pattern drawing in TextOutputDev. 1.00a (2002-feb-25) ------------------- Added an optimized special case for one-bit images in XOutputDev. Implemented CID TrueType font embedding; added a psEmbedCIDTrueType option. The initialZoom X resource was broken. The reverse MacRoman encoding should return 32 for "space" (not 202, which is an alternate encoding). Tweaks to the FreeType 2 support: only disable hinting if the bytecode interpreter is disabled (i.e., disable autohinting but not bytecode hinting); add some padding to the glyph cache for CJK fonts. Added level3 and level3Sep options for the psLevel setting and corresponding -level3 and -level3Sep options to pdftops. Added a -level2 option to pdftops for consistency. Avoid a divide by zero in pdftotext. [Thanks to William Bader.] Added a Greek language support package. [Thanks to Alexandros Diamantidis and Maria Adaloglou.] Don't bother trying to extract a "builtin" encoding from a TrueType font. Accept either a page number or a page reference in a link destination. Update the fontFixedWidth flag in GfxFont after reading the char widths (used by the Acorn RiscOS port). Removed yet another (illegal but not caught by gcc) class specified from a .h file. Avoid using snprintf - it's not available everywhere. Improved the CMYK->RGB transform. Use mkstemps where available. 1.01 (2002-may-20) ------------------ Implemented Type 3 fonts. Implemented PostScript CID font embedding; added a psEmbedCIDPostScriptFonts option. Implemented PostScript 16-bit font substitution; added psNamedFont16 and psFont16 options. Moved the initialZoom setting from X resources to the xpdfrc file. Implemented the radial shading type in the sh (shaded fill) operator. [Thanks to Mike Sweet.] Added an 'include' command to the xpdfrc format. Added the displayNamedCIDFontX option so different fonts can be used within one character collection. Added a simple reverse video mode (-rv switch, xpdf.reverseVideo resource). Implemented stroked text in XOutputDev (with t1lib and FreeType2). [Thanks to Leonard Rosenthol.] Implemented stroked text in PSOutputDev. Added a built-in Unicode map for UCS-2. New key binding in xpdf: 'g' activates the page number text field. PSOutputDev will now embed external TrueType fonts in addition to external Type 1 fonts. The psEmbedType1Fonts and psEmbedTrueTypeFonts options were missing the "Fonts" suffix. Documentation in xpdf.1 for -freetype option was wrong. Added the Big5ascii Unicode map to the Chinese-traditional support package (maps 7-bit ASCII straight through). [Thanks to Lawrence Lai.] Modified the EUC-CN and EUC-JP encodings to pass 7-bit ASCII straight through. [Thanks to Lawrence Lai.] Avoid a divide by zero in XOutputDev. [Thanks to Simon Burge.] Remove old code in openTempFile that removed an extension from the name returned by tmpnam. Tweak the scrolling behavior when switching pages. [Thanks to Case Jones.] In the code that guesses character names (for font subsets), also handle names of the form 'ABnnn'. [Thanks to Colin Granville.] Fix the transform code for annotations. Improved the CMap file parser to handle more general PostScript lexical conventions. Added '-enc' option to pdfinfo. Added the small caps and oldstyle numbers from Adobe's Unicode corporate use area to the Latin1 and ASCII7 Unicode maps. The code in TextOutputDev that guesses Type 3 font size could generate a zero size, which resulted in div-by-zero errors. Various tools (including Adobe's) occasionally embed Type 1 fonts but label them Type 1C - so check for a '%!' at the start. Some tools embed Type 1C fonts with an extra whitespace char at the beginning - just skip over it. Fixed a typo in the Simplified Chinese add-to-xpdfrc file. Updates to dj_make.bat and the djgpp build instructions. Added a Turkish language support package. Updated VMS build scripts. [Thanks to Martin Zinser.] Modify the incremental display update code to redraw less often if most of the commands are vector graphics, as opposed to text and images. Tweak the Type 1 font bbox code to look at the bboxes in both the PDF font object and the embedded font file. Fixed the ETenms-B5-H CMap file (for traditional Chinese) to map the Latin characters to their proportional versions. Added an optional displayCIDFontX entry for one of the Arphic TrueType fonts in the traditional Chinese 'add-to-xpdfrc' file. Remove leading '-' on include statements in Makefiles. Added psASCIIHex parameter. Added the GBK Unicode map to the simplified Chinese language pack. Pdftotext now opens the text file in binary mode to avoid Microsoft's annoying automatic end-of-line translation stuff. Added an executeCommand function in goo/gfile.cc. [Thanks to Mikhail Kruk.] The %ALDImagePosition OPI comment was wrong if the page was scaled to a different paper size. The OPI code was saving the default transform matrix before calling setpagedevice, which can change the matrix. Fixed a crash when an inline image dictionary contains garbage. Upgraded to autoconf 2.53. Use unsigned int file offsets, to allow access to PDF files in the 2-4 GB size range; use fseek64/ftell64 if available. Fixed two floating point exception cases that came up with broken PDF files. Avoid a crash when printing an error message regarding an unnamed font. Default link border width should be 1. [Thanks to Michael Pfeiffer.] Minor tweak to build with FreeType 2.1.0. Handle "weird" characters in PostScript font names. PSOutputDev now handles PostScript XObjects. Added several more page attributes for the pdftex project. Transferred the copyright to Glyph & Cog, LLC. 2.00 (2002-nov-04) ------------------ Switched to the Motif toolkit. Support multiple open documents (in separate windows). Added document outlines to the viewer. Modified the text extraction (placement) algorithm. Implemented the JBIG2 decoder. Added a Latin2 language support package. Added support for movie annotations. Switched back to native LZW decompression code. Text extraction from Type 3 fonts was (partly) broken. The owner password checking code was missing a step in the case of 128-bit encryption. Added the 'printCommands' option to the xpdfrc file. Added key binding for '?' to bring up the about/help dialog. In TextOutputDev, ignore any text that's outside the page bounding box. Text extraction throws away "tiny" characters after the first 20000 per page, to avoid really slow runtimes with PDF files that use special fonts to do shading or cross-hatching; added the 'textKeepTinyChars' option to disable this behavior. Text extraction discards duplicated text (fake boldface, shadow effects). Added ctrl-F as a key binding for find. Added a "find next" function, bound to ctrl-G. Added ctrl-P as a key binding for print. Modified the DCT decoder to handle progressive and non-interleaved JPEG streams. Added key bindings for ctrl-Home and ctrl-End. Allow the initialZoom setting to be made in either the xpdfrc file or as an X resource. Added a Hebrew language support package. [Thanks to Roy Arav.] The "make distclean" target now creates (empty) Makefile.dep files in the three subdirectories. Initialize XRef::ownerPasswordOk. Correctly handle stroking of Type 3 fonts in PSOutputDev. Generate correct PostScript for fonts with "weird" character names (e.g., "("). Generate correct PostScript for images using Indexed color spaces with DeviceN base color spaces. Added lowercase Roman numerals to ISO-2022-CN.unicodeMap (simplified Chinese support package). Tweak the image scaling code to better handle flipped (top-bottom and/or left-right) images. Generate correct PostScript code for inline images and images in Type 3 fonts which are too large for a single PS string. Correctly handle indexed color spaces whose base color spaces have component ranges other than [0,1]. Optimized the DCT decoder. Fixed mistakes in the list of key bindings in the about/help dialog. Optimized the Flate decoder. Add literal names for punctuation and digits to the Unicode name table. Cygwin's popen wants mode "r", not "rb". Fixed a bug in the Type 4 function parser (the "if" operator wasn't parsed correctly). Fix a bug in PS output for TrueType fonts with no PDF encoding. Make the bbox size in FTFont more liberal (to avoid problems with fonts that have incorrect bboxes). Reverse the colors in PBM files generated by pdfimages, so the common case (an image mask filled with black) comes out correct. Add fseeko/ftello support which is basically identical to fseek64/ftell64. [Thanks to Nassib Nassar.] Modified column assignment in text extractor to account for characters that convert to multiple characters in the output encoding. Fix TrueType fonts which have an incorrect cmap table length. Work around a pragma bug in the version of gcc that ships with MacOS X 10.2. [Thanks to Frank Siegert and Andrew Stone.] Fix a problem that was causing an infinite loop when a damaged content stream contains an 'ID' command inside a dictionary. Handle the case where systempapername() returns NULL (libpaper support). Handle fonts which are defined directly in the font resource dictionary rather than as separate objects. Track process colors in Level 1 separable PostScript. Pdfinfo now checks the return value from mktime to avoid seg faults in flakey strftime implementations. If duplex is not enabled in PostScript output, leave the duplex setting alone, allowing the spooler to insert its own setting. Added three missing fclose calls. Change the default encoding for TrueType fonts (used when the PDF file doesn't specify an encoding) from MacRomanEncoding to WinAnsiEncoding. Move X_CFLAGS to the end of the list in CXXFLAGS (in Makefile.in) to avoid some of the FreeType2 include path problems. Fixed an obscure bug in the LZW decoder. [Thanks to Martin Schroeder.] Fixed a bug in decryption when using the newer (PDF 1.4) algorithm with shorter-than-128-bit keys. Minor optimization for image data streams: the ImageStream class can return an entire buffered line. 2.01 (2002-dec-05) ------------------ Redesigned the text extraction process: - process the text into "reading order" - added a "-layout" flag to pdftotext to switch back to the old style, where physical layout is maintained - use of the "-raw" flag is no longer recommended Added the -reload option for xpdf (in remote mode). Added support for external CID fonts; added the displayCIDFontT1 and displayNamedCIDFontT1 commands to the xpdfrc file. Handle the case of moveto/newpath/clip, which defines an empty clipping region (just like moveto/closepath/clip). Accept XYZ link destinations with missing array elements. Fix some problems with state save/restore triggered by Type 3 fonts that reference other fonts. Accept bogus font names based on "Symbol": Symbol,{Bold,Italic, BoldItalic}. Fixed color and font resource names in the xpdf man page. Was using delete instead of gfree in OutlineItem::~OutlineItem. Set the busy cursor in the find dialog while searching. Map variants of the copyright, trademark, and registered trademark symbols to the proper Unicode codes, not to Adobe's corporate use area codes. Fixed a floating point exception bug in TextOutputDev (check for a too-small denominator). Fixed a typo in TextOutputDev, in the code that generating blank lines to add vertical whitespace. Config files whose last line didn't end with a LF (or CR+LF) weren't being handled correctly. The code that handled CIDToGIDMaps in Type 2 CIDFonts was broken. Check the per-glyph bounding box in Type 3 fonts, and don't try to cache glyphs with bogus bboxes. Allow ToUnicode CMaps to use fewer than four hex digits in the Unicode char indexes. Added multithreading protection to the GlobalParams class. Fixed a bug in end-of-stream detection with the TIFF predictor. Added some characters to MacRomanEncoding to match up with Apple's definition. 2.02 (2003-mar-24) ------------------ Rewrote the text extractor code that assembles words into lines to better handle vertically overlapping lines. Add the "match" option for paper size (in PostScript output). Added support for external 16-bit TrueType fonts; added the displayCIDFontTT and displayNamedCIDFontTT commands to the xpdfrc file. Added an Arabic language support package. Added the Windows-1255 encoding to the Hebrew language package. A missing NULL check was causing a crash when closing the file in a single window (which clears out the window, but leaves it open). Deal with TrueType fonts whose glyph data is out of order - this affected both FreeType rasterization and PostScript generation. Munge font names in PSOutputDev to avoid names that are problematic for ghostscript because they start with an out-of-limits number (e.g., 1e999foo). Modify the TrueType font encoding deciphering algorithm in yet another attempt to match up with Acrobat's behavior. Bounds check the indexHigh value in indexed color spaces. The text extractor no longer bothers trying to get an average character width for Type 3 fonts, since it generally doesn't work very well (because Type 3 metrics are unreliable). Don't crash if the user hits ctrl-G ("find again") before doing a find. Set the button pixmap foreground color correctly. Handle text drawn backward on 180 degree rotated pages. Added a magic call to XtUngrabButton after calling XmCreatePopupMenu which appears to prevent some very odd problems (idea taken from the DDD source code). Fix the MacOS X fix (needed to include ). Fixed a bunch of Motif 1.x / X11R5 incompatibilities. [Thanks to William Bader and Albert Chin-A-Young.] Fixed various bugs in previously untested code in the JBIG2 decoder. Modify the XPDFCore destructor to avoid a bogus warning message from OpenMotif 2.2. Modified the Type 1C font parser to do proper bounds checking. Fixed the bounds checking in the TrueType font parser. Text extractor shouldn't do block merging in physical layout mode. Fixed a problem in PSOutputDev in level2sep mode with images in a Separation color space and with a non-default Decode array. Text extraction with "-raw" was concatenating lines from the bottom of one column and the top of the next. Handle Type 1C subroutines in the font converters. Correctly handle progressive JPEG images whose scans are slightly different sizes (e.g., the Y scan rounds up to a multiple of 8 pixels and the Cb/Cr scans round up to 16 pixels). Avoid a potential divide-by-zero problem in TextOutputDev. Modified the T1Font and FTFont modules to correctly handle glyphs that are larger than the font's claimed bounding box. Tweak dupMaxDeltaX parameter in TextOutputDev to avoid triggering on double characters. Improved detection in pdfinfo for ISO paper sizes. [Thanks to Hartmut Henkel.] Xpdf wasn't responding to the TARGETS atom, which prevented pasting the selection into various applications. [Thanks to Phillip Ezolt.] Handle XObjects with recursive references in their Resources dictionaries (in PSOutputDev). Change PSOutputDev to deal with invalid PDF files that use non-embedded TrueType fonts with no encoding. Check for undersized Widths arrays in fonts. Add bounds checking code to Array class. Updated VMS build scripts. [Thanks to Martin Zinser.] Tweak the TrueType font handling code (again): - char codes in symbolic fonts may or may not be offset by 0xf000 - discard empty tables because they sometimes confuse FreeType Fixed bounds checking in the Flate decoder. Removed a bogus error message for exponential functions without explicit C0/C1 values. [Thanks to Hartmut Henkel.] Handle the other Unicode cmap type (platform=0) in TrueType fonts. Added support for the SGI Motif horizontal paned window widget. [Thanks to Felix Ritter.] Ignore extra elements in link destination arrays. Accept external Type 1 font files with a suffix of ".ps" or no suffix at all. Add a bounds check in the DCT decoder. Added instructions for building xpdf.exe under cygwin/XFree86. Tweaked the word separation parameter for raw-mode text extraction. 2.03 (2003-oct-10) ------------------ Rewrote the text extractor to: - do a better job with rotated text; - handle right-to-left scripts; - be faster. Changed the zoom setting to use a percentage (relative to 72 dpi) instead of a zoom "factor". If the PDF file has an outline, open the outline pane initially. Added -f and -l options to pdfinfo; print multiple page sizes. The HAVE_XTAPPSETEXITFLAG test in XPDFApp.cc was backwards. The BitsPerComponent entry is optional in image mask objects. Render any annotation with an appearance stream, instead of just Widget and Stamp annotations. Fix a bug in the TrueType font checker: the test for an unsorted 'loca' table was wrong. Modify the TrueType cmap selection algorithm yet again to try to match Adobe's behavior. Changed sqrt(2) to sqrt(2.0) in pdfinfo.cc to make various compilers happy. Fixed a deadlock problem (when MULTITHREADING is set); cleaned up some other problems with the locking code. Fixed a bug in the interpolation code for type 0 (sampled) functions. Implemented type 1 (function-based) shaded fills. Fixed some stupid bugs in the JBIG2 decoder (introduced with the previous optimization work). Fixed a typo in the code that parses vertical font metrics for CID fonts that was causing a seg fault. Fixed a couple of bugs that were causing seg faults with badly damaged PDF files. Limit the number of nested Forms to avoid infinite recursion (in buggy PDF files). Add a special case for rectangular clip regions - make sure these don't drop pixels on the right and bottom edges. Tell FreeType not to use glyph bitmaps when in anti-aliased mode. Read all of the border style info for links. All of the shaded fill types now do at least one bisection to avoid problems when the colors at the endpoints of the domain are the same. If the Length2 parameter for an embedded Type 1 font was incorrect (too small), pdftops was losing font data. Deal with (broken) DCT streams that use the same component ID number for different components. The MediaBox page attribute was not being inherited correctly. Fixed a bug in the Type 1C font converter related to local subroutines. The Type 1C -> Type 1 font converter was allocating the font dictionary one slot too small. Added a missing private dictionary entry to Type 1 fonts generated by the Type 1C converter. [Thanks to Michael Shell.] Fixed bugs in the tiling pattern fill code. Try the TrueType 0xf000 char code offset hack for the MacRoman encoding too (in addition to MS Symbol). Update the font metrics info for the Base 14 fonts to include the Euro character. SECURITY HOLE: Escape various characters in URLs before running a web browser (or movie viewer). [Fixed in 2.02p11] SECURITY HOLE: In the dialog used to verify "launch" links, provide a scrolling view if the command to be run is excessively long. [Fixed in 2.02p11] Added an option to disable insertion of page breaks (form feed characters) in extracted text (pdftotext -nopgbrk; xpdfrc "textPageBreaks" option). Check for 8-bit fonts that specify an out-of-range FirstChar or LastChar. Correctly handle an obsolete Type 2 charstring op (in the Type 1C-to-Type 1 font converter). [Thanks to Helge Blischke.] Use the font encoding info to fill in holes in the ToUnicode map. Added character names for Bulgarian (in the Cyrillic support pacakage) and Greek. Handle clipping to text in xpdf and pdftops. Fix color space detection in DCT decoder. [Thanks to Dwight Kelly.] Added the "unicodeToUnicode" xpdfrc option, intended (initially) for Arabic support. Handle the case in PSOutputDev where two font objects refer to the same embedded TrueType font, but with different encodings. [Thanks to Frank Siegert.] Kill any pre-existing path before drawing a form (or annotation). Save state before rendering page content; restore state afterward. Fix Stream::reset/close to work correctly with encoder streams; fix PSOutputDev to use Stream::close consistently. Fix a seg fault when hitting the 'back' button after closing a file. GfxState::getStrokeGray was returning the fill gray value (this only affected Level 1 PS output). Change PSOutputDev to reuse dictionaries in Level 1 mode (since Level 1 PS interpreters don't do garbage collection). [Thanks to Frank Siegert.] PSOutputDev was generating incorrect translations for landscape-mode pages. Implemented shading pattern color spaces. PSOutputDev wasn't correctly handling Type 3 fonts which used image resources (as opposed to inline images). [Thanks to Frank Siegert.] The fix from 1.00 which clipped out-of-bounds points was a bit too aggressive. Do proper Floyd-Steinberg dithering in XOutputDev. Don't automatically check for a null owner password (to match Adobe's behavior). Allow the FlateDecode filter in Level 3 PostScript output. Fixed small bugs in the Type 1C -> Type 1 converter and Type 1C -> Type 0 converter. [Thanks to Tom Kacvinsky.] Work around another weird Motif problem with the right button menu (which was sometimes causing the menu to not be displayed). Make the code that handles fonts defined directly in the resource dict more robust. Add a brief description of the outline pane to the xpdf man page. Ignore extra operands to content stream operators. Fixed a bug in the CCITTFax decoder. Allow the Count entry in a Pages dictionary to be a real number (because some PDF generators actually do this). Shading pattern fills weren't being clipped correctly. Incorrect shallow copies in GfxRadialShading and StitchingFunction. The StitchingFunction destructor wasn't checking for funcs being NULL. Change the TrueType code-to-GID mapping code so it looks at the TrueType 'post' table. Set the print command in the print dialog once at startup, don't change it each time a file is (re)loaded. Generate the %%BoundingBox comment in regular PostScript files (not just EPS files). Fixed a bug in the Unicode CMap parser. 3.00 (2004-jan-22) ------------------ New PDF rasterizer ("Splash"). Added support for PDF 1.5: - JPX (JPEG 2000) decoder - XRef streams - object streams - DeviceN color spaces with up to 32 components - Added new CMaps to the CJK language support packages Replaced pdftopbm with pdftoppm (which can generate PBM, PGM, and PPM files). Reorganized the font file parser code into a new library ("Fofi"). Removed support for FreeType 1.x. Removed support for X server fonts - Xpdf (and pdftoppm) will now search for the URW fonts (from ghostscript). Changed the "-t1lib" and "-freetype" switches; replaced the "t1libControl" and "freetypeControl" config file options with "enableT1lib", "enableFreeType", and "antialias". Added the "-box" option to pdfinfo. Added imageable area support to PSOutputDev (for CUPS); added the "psImageableArea" config file option. Added the "-nocrop", "-expand", "-noshrink", and "-nocenter" switches to pdftops; added the "psCrop", "psExpandSmaller", "psShrinkLarger", and "psCenter" config file options. Dictionary size was in PostScript code generated for Type 3 fonts. The PS code generated for images in Type 3 characters was broken. Tweaked the text extractor. Accept xref entries that are one byte too short (matching Adobe's behavior). Change things so "xpdf -h" and "xpdf -v" work if DISPLAY isn't set. Fix a problem in the damaged file repair code that handles the trailer dictionary. Use the "Last" entries in "Outlines" objects - this avoids a problem with PDF files generated by buggy software that, e.g., sets the last item's Next pointer to point to itself. PSOutputDev was not handling DeviceN color spaces correctly in Level 2 images. Fixed a stupid little bug that broke PS output for JBIG2 images. Work around a Lesstif bug: set up an extra callback so hitting in the find dialog performs a search. [Thanks to Elliott Hughes.] Pdftops was crashing on zero page PDF files. Add an AC_PREREQ call to configure.in. Change the 'find' dialog so the text entry box resizes with the dialog. Skip extraneous zero bits at the start of a CCITTFax stream. The PostScript text clipping operator was missing a 'newpath'. [Thanks to Frank Siegert.] Fix a bug in tiling patterns with bboxes that don't start at (0,0). Fix a bug in Type 3 font handling with rotated text. The tiled pattern fill code was destroying the current path, which broke the fill+stroke operators when the fill color space was a tiled pattern. ICCBased color spaces don't always set their Ranges values correctly, so just use the values from the alternate color space. Modified GHash to accept int or void* - this avoids some conversion warnings. Check for missing Type 3 CharProcs - avoid a segfault. Pdffonts now marks all Type 3 fonts as embedded. Outline entries with no Title string weren't being handled correctly, resulting in segfaults. PSOutputDev now forces the text horizontal scale factor to be non-zero to avoid singular font matrices in the PS code. Tweaked the error recovery in the CCITTFax decoder. The LZW/Flate predictor should treat any Predictor value (in the stream dictionary) >= 10 identically. PSOutputDev and pdffonts check for NULL font objects (which can happen, e.g., because of missing CMap files). Swap the left and right mouse wheel button numbers. EPS output ("pdftops -eps") now uses the CropBox instead of the MediaBox as the EPS bounding box. 3.01 (2005-aug-17) ------------------ Added the continuous view mode, including the '-cont' switch and the 'continuousView' config file option. At high zoom levels, don't rasterize the entire page - this avoids problems running out of memory. Added "search backward" and "match case" options to the find dialog. Support explicitly masked images and soft masked images. Add support to DCTStream for 16-bit quant tables. Don't segfault if the user clicks on an outline entry with a broken destination. Changed the makefiles and configure script to skip building pdftoppm (in addition to xpdf) if X, Motif, or FreeType is not found; changed the error message in the configure script to match. Move an inline function in JArithmeticDecoder.cc to avoid compiler errors. Fixed a bug in the rasterizer that was sometimes causing infinite loops with round line caps on vertical lines. Various rasterizer optimizations. Look for intermediate resize events - try to avoid lagging when the user is doing an opaque resize. The FormType key in Form XObjects is optional. Handle external 16-bit TrueType fonts correctly, using the Unicode cmap. Add class declarations to TextOutputDev.h to work with stricter C++ compilers. Support FreeType's weird include file stuff (ft2build.h, etc.). Fixed a bug handling empty paths. Fixed a text positioning problem in PostScript output. Handle TrueType collections in FoFiTrueType.cc. FoFiTrueType constructor was reporting a failure if the post table was bad - this should be non-fatal. Type 1 font parser was missing a NULL test. Mask chars passed to isdigit in goo/parseargs.c to avoid problems with signed chars. Added more error checking to the CCITTFax decoder. Fixed a bug (computing the MCU size) in the DCT decoder. Change a test in the Splash stroke code to avoid x86 floating point weirdness. Reorganized the decryption code to allow security handler plugins; removed the NO_DECRYPTION #ifdefs. Added a plugin interface, initially just for security handlers. Support color key masked images and explicitly masked images in PS output (Level 2 only). When checking for aliases of the Base 14 fonts, ignore spaces in the specified font name. Handle encrypted PDF files that are missing the file ID string. Handle tiling patterns more efficiently in the PostScript output. Rewrote the code that handles color spaces in PostScript output. Fixed a bug in the Type 1C font parser - zero-length indexes (and zero-length names) weren't handled correctly. Handle shaded fills more efficiently in the PostScript output. Implement the remaining shading types (4-7). Rearranged the Splash color modes. Add the EarlyChange parameter to LZWStream when generating PostScript. Check for zero values in line dash arrays in PSOutputDev. Fixed an uninitialized variable in JArithmeticDecoder which was causing crashes. Treat unknown CMap names as identity mappings (to match Adobe's behavior). Fixed bugs in the XRef parser related to XRef streams in updated files. Added a missing call to FT_Done_Glyph which was causing a memory leak. [Thanks to Dave Formanek.] Fixed a bug in text copying that was causing the last word to be dropped on some pages. Tweaked the image width/height computation in Splash::drawImage and Splash::fillImageMask to make striped images work better. Ignore minus signs in the middle of numbers (to match Adobe's behavior). Missing '%s' in format strings for dates in pdftotext '-htmlmeta' mode. Change the TrueType code-to-GID mapping code so it looks at the standard name-to-Unicode mapping before the ToUnicode mapping defined in the font object. Added a matteColor setting (command line option and X resource). Tweaked the CMYK->RGB transform. Fix some problems in tracking the character position (to match up with Adobe's highlight file format). Handle moveto/closepath/stroke correctly. Check for singular text matrices and font size of zero in PSOutputDev. Clip PS output to the size of the page (avoiding any gibberish that lies outside the MediaBox, in the case where the MediaBox is smaller than the paper). If the line dash element in an annotation's Border array is of an invalid type (i.e., not an array), don't draw the link at all (this matches Adobe's behavior). Don't remap small caps and oldstyle glyphs in the name-to-Unicode table - it messes up TrueType font encodings. Pdftoppm wasn't setting the paper color correctly in mono and gray modes (this only showed up on big-endian machines). Missing NULL check was causing crashes when attempting to read non-PDF files that happened to contain the string '%PDF'. Fixed a problem in the text extractor that was breaking up words. Handle vertical text (CJK fonts) in PS output with TrueType fonts that are missing the vertical metrics tables. Handle the case where a font object and the corresponding embedded font are different types. Handle basic crypt filter functionality. Added more value checking in the XRef parser, to avoid potential security problems. Updated the CJK language support packages: replaced the displayCIDFontX references with displayCIDFontTT; added pointers to free TrueType fonts. Added a missing error message when SplashOutputDev can't parse an embedded TrueType font file. PDFCore and TextOutputDev now correctly handle searching for Unicode strings, including real Unicode case-folding. Throw away tiling pattern fills that are completely outside the clip region. The JPEG 2000 inverse reversible multiple component transform code was wrong. Fixed some bugs in shading pattern fills: clipping was wrong, and background color was not implemented. Added tool tips for the toolbar buttons. Decrease the max depth of recursive patch mesh filling if the pattern has a large number of patches. Highlight the find text whenever the find dialog is mapped. Handle page boundary boxes with reversed coordinates. Fixed a bug in the text extractor code that handles duplicated text. Optimization work on SampledFunction::transform(). Use the CropBox instead of the MediaBox as the display region. Dither for PseudoColor (8-bit) displays. Fix a bug in DCTStream that was causing an infinite loop with corrupted DCT image data. Fix a bug in the ToUnicode CMap parser. Fix a bug in the text extractor - negative font sizes weren't being handled correctly. Fix a bug in the text extractor - in certain cases, out-of-bounds text could cause crashes (generally only in damaged PDF files). Fix a read-past-end-of-array bug in the JBIG2 decoder. Fix a case where pdftops was generating lines longer than 255 chars. Optimize redraws - don't regenerate the XImage every time redrawRect is called. The ASCII85 decoder wasn't skipping whitespace properly. Optimize text extraction: skip (non-inline) image setup entirely. Added initial transparency support (stroke/fill alpha and blend mode). Added support for the overprint setting in PostScript output. Fixed various buffer overflow bugs. Handle negative font sizes and horizontal scaling correctly - this affected PSOutputDev for all text operators, as well as the TJ operator for all OutputDevs. Fixed a buffer overflow in the CCITTFax decoder. Fixed an out-of-order entry in the list of font name aliases. Fixed a backward loop in the PostScriptFunction code. Treat a zero-length base URI the same way as a nonexistent base URI. Add a divide-by-zero check in TextOutputDev (the problem was happening in cases of mixed horizontal and vertical text). PSOutputDev wasn't rounding the page bounding box coordinates correctly. Support the SOF1 marker in DCT (JPEG) image streams. Minor changes to GlobalParams.h and JPXStream.h because some compilers don't like anonymous structs inside anonymous unions. Xpdf now complains about a negative page number. Changed GString::cmp and GString::cmpN to correctly handle '\0' chars in the middle of strings. Fixed the radial shading code; corrected the handling of the 'extend' parameters. Added the gmallocn and greallocn functions. Fixed a bug in the TIFF image component predictor which shows up with components that are not 1 or 8 bits wide. Optimized FlateStream::loadFixedCodes(). For non-embedded Base-14 fonts, don't use the ascent/descent/bbox values from the FontDescriptor - various PDF generators get them wrong. Fixed a bug in the text extractor - words on the same line (especially in tables) were being split vertically onto multiple lines. Automatically select the correct radio button ("print with command" vs. "print to file") in the print dialog. Don't create the "open" and "save as" dialogs until needed - this avoids stat-ing every file in the directory at startup. Changed the Big5 and Big5ascii encodings (in the traditional Chinese language support package) to include characters from the Unicode database (which aren't mentioned in the Adobe character collection documentation). Added the '-pagecrop' switch to pdftops. Tweaked the RGB->gray and CMYK->gray conversion functions to match the PDF spec. The JPEG 2000 decoder wasn't correctly handling codeblocks split across multiple packets/layers. Fixed a typecast that caused compile errors on 64-bit systems. The CMap parser wasn't handling the 'cidchar' construct. Handle the case in PSOutputDev where two font objects refer to the same embedded 16-bit TrueType font, but with different CIDToGIDMaps. Changed the configure script to report more accurate warnings when it can't find X / Motif / FreeType. Encryption with revision=2 always uses a 40-bit key, regardless of the specified Length value. Yet another minor change to the TrueType font encoding deciphering algorithm. Don't completely invalidate the Catalog if one (or more) of the page objects are bogus -- just skip over those pages. Removed the workaround in pdftops for too-small Length2 values in Type 1 fonts -- it was causing problems on various PostScript printers. Started adding error checking to the JBIG2 decoder (this is nowhere near complete yet). Extended the "unicodeToUnicode" config option to also apply to CID fonts. Added the narrow Latin characters to the Adobe-Korea1.cidToUnicode file in the Korean language support package. Fixed the code that handles page rotation in PSOutputDev. When converting a Type 1C glyph to a Type 1 glyph, insert closepath operators as appropriate. Check for a sane 'loca' table in TrueType fonts (FoFiTrueType::parse). Fix PSOutputDev to correctly handle the case of an empty name in a font encoding. 3.02 (2007-feb-27) ------------------ Added anti-aliasing for vector graphics; added the vectorAntialias xpdfrc option; added the "-aaVector" switch to xpdf and pdftoppm. Implemented stroke adjustment (always enabled by default, ignoring the SA parameter, to match Adobe's behavior), and added the strokeAdjust xpdfrc command. Support PDF 1.6 and PDF 1.7. Added support for AES decryption. Added support for OpenType fonts (only tested with 8-bit CFF data so far). Added user-configurable key/mouse bindings - the bind/unbind xpdfrc commands. Cleaned up the full-screen mode code and added the ability to toggle it on the fly (the default key binding is alt-f). Pdfimages with the -j option now writes JPEG files for 1-component (grayscale) DCT images, in addition to 3-component (RGB) images. Fixed bugs in handling sampled (type 0) functions with 32-bit samples. Fixed some things to support DeviceN color spaces with up to 32 colorants. Pdftops now constructs the %%Creator and %%Title DSC comments from the relevant information in the PDF Info dictionary. Tweak the TrueType font encoding deciphering algorithm. Added the "mapUnkownCharNames" xpdfrc option. Fix a bug (that only showed up with certain window managers) in the intermediate resize event optimization. [Thanks to Michael Rogers.] Check for a broken/missing embedded font (this was causing xpdf to crash). Added support for transfer functions in PostScript output. Be a bit more tolerant of Link destinations that contain null values for positioning parameters. Use ordered dot dithering instead of clustered dot dithering at resolutions below 300 dpi (for monochrome output). Fixed security holes (bounds checking issues) in several places. Don't bother creating a SplashFont (allocating memory) for fonts that are only used for hidden text - this avoids problems with fonts of unreasonably large sizes. Clipping in TextOutputDev was off for characters on the left edge of the page. The scn and SCN operators weren't correctly handling colors with more than four components. FoFiType1::writeEncoded wasn't always correctly finding the end of the encoding. Use the ColorTransform parameter in the DCTDecode stream dictionary. Type 3 fonts are allowed to have a bbox of [0 0 0 0], which means "unspecified" -- don't issue error messages in that case. Perform the transform (to device space) in Splash instead of in SplashOutputDev -- this is needed to correctly handle round joins and caps on stroked paths. PSOutputDev now rasterizes any pages that use transparency. Limit the crop, bleed, trim, and art boxes to the edges of the media box (per the PDF spec). Change GString to increase the allocation increment by powers of two. Handle whitespace in hex strings in CMap files/streams. Use strings instead of names for separation colorant names in PSOutputDev. For explicitly masked images where the mask is higher resolution than the image, use the soft mask code. Avoid problems with very large x-steps in the PostScript output for tiling pattern fills. Avoid a divide-by-zero in stitching functions which have a subfunction with empty bounds. Honor the "Hidden", "NoView", and "Print" flags on annotations. Rewrote the pixel rendering code in Splash to use a single set of pixel pipeline functions. Added support for transparency groups and soft masks. Fixed the transparency blend functions to match the addendum published by Adobe. Changed Splash/SplashBitmap to store alpha in a separate plane. Setting the color space now selects the correct default color for that color space. Remove the mutex lock from GlobalParams::getErrQuiet() to avoid a deadlock when parseCIDToUnicode() or parseUnicodeToUnicode() calls it from inside a locked section. Added error checking (on the argument count) in the sc/SC/scn/SCN operators. Skip over notdef glyphs in TrueType fonts (which sometimes get drawn as little boxes), to match Adobe's behavior. Painting operations in a Separation color space with the "None" colorant or a DeviceN color space with all colorants set to "None" never mark the page. Fixed an obscure bug in the JPX decoder - it wasn't reading the extra stuffing byte in the case where the last byte of a packet header was 0xff. Change the TrueType font parser (FoFiTrueType) to change the glyph count rather than report an error if the 'loca' table is too small. Fixed a couple of bugs in the JBIG2 decoder. Added stochastic clustered dot dithering. Added the screenType, screenSize, screenDotRadius, screenGamma, screenBlackThreshold, and screenWhiteThreshold xpdfrc settings. PSOutputDev now correctly handles invalid Type 3 charprocs which don't start with a d0 or d1 operator FreeType 2.2.x support - get rid of the FT_INTERNAL_OBJECTS_H include, and add some 'const' declarations. Handle PDFDocEncoding in Info dictionary strings. Tweak the xref repair code - ignore whitespace at the start of lines when looking for objects. Added the "-exec" switch to xpdf. Removed the xpdf.viKeys X resource. Changed the color key / explicit masked image code in PSOutputDev to generate better PS code, including a Level 3 option. Tweaked the DEBUG_MEM code for performance. Move the JBIG2 global stream reading code into reset() instead of the constructor - this way, pdftotext doesn't end up reading the global stream. Added the "-preload" option to pdftops and the psPreload xpdfrc command. Added the "zoom to selection" command (on the popup menu). Fix a bug (in xpdf/pdftoppm/pdftops) with tiling patterns whose bbox size is different from their xStep/yStep. Implemented stroke with pattern color spaces. Following a link to a page whose CropBox was different from the MediaBox was resulting in an incorrect scroll position. Parse truncated date strings from the Info dictionary correctly. Change FoFiType1 to handle Type 1 fonts with two /Encoding keys. Extend the PSOutputDev shaded fill code to handle DeviceCMYK shaded fills in level2sep and level3sep modes. Detect infinite loops in the Page tree. Optimized the ASCII85Encoder code. Tweaked the text extractor to do a better job of lining up rows of text. Leave images compressed (or re-compress them with RLE) in PostScript output when setting up images for forms and Type 3 fonts (or with -preload). Extend FoFiType1 to handle Type 1 fonts with octal character codes in their encodings. Use a custom string formatter to avoid problems with locale-based decimal formatting (commas instead of periods) in PS output. Allow comments in PostScript-type functions. Change the TrueType font parser (FoFiTrueType) to delete glyf table entries that are too short. 3.03 (2011-aug-15) ------------------ Added the "fixed pitch" text extraction mode. Modified "pdftops -paper match" to handle PDF files with different-sized pages, i.e., it will now select the matching paper size on a page-by-page basis. Add ability for pdftoppm to write to stdout. Added the pdfdetach tool. Implemented 256-bit AES decryption. Commented out the t1lib section in the configure script -- t1lib has some potential security holes, and hasn't been updated in years. Redesigned the font configuration xpdfrc commands: removed the displayFontT1, displayFontTT, displayNamedCIDFontT1, displayCIDFontT1, displayNamedCIDFontTT, displayCIDFontTT, psFont, psNamedFont16, and psFont16 commands; added the fontFile, fontFileCC, psResidentFont, psResidentFont16, and psResidentFontCC commands. Switched from GPLv2 to dual v2/v3 licensing. Performance: cache tiling patterns. Implemented text fills with pattern color spaces. Rewrote the image and image mask rendering code to be more accurate and faster. Fixed a bug in PDFCore that could sometimes cause crashes at high zoom levels. Implemented embedded CMap streams. Added the 'setSelection' command. Added the 'rotateCCW' and 'rotateCW' commands. Added the 'psFontPassthrough' xpdfrc command. Added the 'launchCommand' xpdfrc command. Implemented alpha-type soft masks. Added "Form: AcroForm|XFA|none" to pdfinfo output. Added support for image masks filled with pattern color spaces. Text search wasn't finding all occurrences of a string on rotated pages (i.e., pages where the primary rotation, as displayed, was not horizontal). The text extractor now uses "ActualText" spans if they are present. Modified PSOutputDev so it always check for transparency; if Splash is not available, it now prints a warning. Handle the blending color space for soft masks. Added the disableFreeTypeHinting xpdfrc option. Added the psAlwaysRasterize xpdfrc option. Added support for transfer functions in the rasterizer. Optimized the JPEG 2000 decoder to use less memory. Do fill adjustment (similar to stroke adjustment) on simple rectangular fills. Added the antialiasPrinting xpdfrc setting. Added '%i', '%j', and '%k' (mouse pointer page and position) to the available options for the 'run' command. Links with the underlined border style were being drawn with the lines over, instead of under, the text. Add #include to XPDFTree.cc (to avoid problems with certain compilers). Change XRef::fetch() to avoid infinite loops caused by odd damage to the xref table (e.g., where a stream object's "Length" value is an indirect reference that points to another stream object). Minor fix in GString.cc to deal with an error in newer C++ compilers (pow() can take int or double args). Handle embedded fonts which are declared with the wrong font type, including 8-bit fonts declared as CID fonts and vice versa; this was causing various problems, including crashes and invalid PostScript output. In text extractor, don't drop horizontally overlapping words onto a separate line. The numbers in the operand to the TJ operator should be multiplied by the current horizontal scaling parameter. Fixed a bug in the Type 1C-to-Type 1 font converter -- need to escape strings in the font dictionary. The zero-font-size check in PSOutputDev.cc was broken. Fixes for the form field appearance regeneration code: handle Unicode strings (by downconverting to Latin1); check for "True" in addition to "Yes" as a button value. Modify XPDFTree to limit the widget height to 32767 pixels -- this avoids crashes with very large outlines. Modify FoFiType1 to handle PFB headers in Type 1 font files. Allow image mask decode arrays to be [1.0 0.0] in addition to [1 0]. Tweak the form field appearance regeneration code. PSOutputDev now sets up resources for DR dictionaries in forms (in case the form field appearances are regenerated). For TrueType fonts which are marked symbolic, the cmaps should be ignored. Change the handling of numeric characters in Unicode text output -- they are now treated as left-to-right, which isn't strictly correct, but does result in correct visual formatting. Modify FoFiTrueType to handle bogus loca table entries where the offset is past the end of the glyf table. Fixed shading pattern fills to do clipping and background fills correctly. Change the code that reads the page tree to be more flexible with regard to improperly constructed trees. Changed the PostScript header comment from "Produced by xpdf/pdftops x.yy" to "XpdfVersion: x.yy" to make it (mostly) DSC-compliant. Fixed PSOutputDev to handle page rotation correctly where the PDF page is rotated 90 or 270 degrees and the page width (before rotation) is greater than its height (and vice versa for 0 or 180 degrees). Unbalanced save/restores inside form XObjects (which can be happen in damaged or incorrectly constructed PDF files) could cause crashes. The CCITTFax decoder could go into an infinite loop on certain types of corrupt input. Added the "drawAnnotations" xpdfrc command. Added the "psUncompressPreloadedImages" xpdfrc command. Escape newlines and other non-printable characters in the custom color DSC comments in PostScript output. Added the tilingPatternFill and *ShadedFill functions to PreScanOutputDev to speed it up. Too many elements in an image's Decode array should not be a fatal error. Fixed a buffer overflow security hole in StreamPredictor. Empty pages (zero-length content streams and null contents) were causing crashes in continuous view mode. Handle line dash arrays that start with a zero element correctly. PreScanOutputDev was not correctly detecting all transparency - in some places, it was looking only at the blending mode, and not at the opacity setting. Force halftone screen size to be a power of 2. This allows optimizing the halftoning code. Fixed a bug in the JBIG2 MMR decoder (and also in the CCITTFax decoder) that was causing array references with negative indexes. Fixed a bug in the transparency code that was causing memory overruns. Fixed a 64-bit bug in the ASCII85 encoder. The focusToPageNum was crashing in full-screen mode - it should simply do nothing. Added '%p' (current page number) to the available options for the 'run' command. Tweak the behavior with PDF files that have pages of different widths in continuous mode: scroll horizontally to avoid blank space on the left side (when changing pages via entering a page number or clicking on a link). A closepath followed by a lineto should create a new subpath for the lineto. Fixed a buffer overflow in the CCITTFax decoder. Adobe Acrobat appears to ignore the flatness setting when rasterizing curves, so Xpdf now does the same. (Oddly, Acrobat passes the flatness setting through to PostScript output, which ends up making the PS file look different from the PDF file - so Xpdf continues to pass flatness through to PS files, too.) Pdfimages now ignores tiling pattern fills (for performance reasons). Fixed a bug in PDFCore that could sometimes cause crashes at high zoom levels. Use std::sort (with functors) in place of qsort (if available) - this can be significantly faster. Hitting "close" while Xpdf is in full-screen mode (with only one file open) was crashing. Tweak the TrueType font encoding deciphering algorithm. Rewrote the CCITTFax decoder inner loop - this fixes a security hole. Fixed two security holes (missing bounds checks) in the DCT decoder. Do the correct zooming for "Fit" and "FitR" destinations. Implement the rotation value in the form field appearance regeneration code. When PSOutputDev rasterizes a page (because it contains transparency), the image is broken into stripes if it is above a size threshold. Don't clip the other page boxes to the MediaBox at the intermediate (Pages) nodes; only do it at the leaf (Page) nodes - the other boxes can be specified before the MediaBox is specified. Split several special cases off from Splash::pipeRun, for performance. Add a sanity check for excessively large font sizes (which caused problems because Xpdf tried to allocate memory for a font cache). Fixed a bug in the GfxCIDFont constructor involving reading the vertical metrics. Rewrote the code that handles annotation transforms - it was not handling non-rectangular transforms correctly. Tweak the Type 3 bbox code to allow some slack on the left/bottom edges, as well as the top/right edges. Fixed a bug that was causing problems rendering Type 3 fonts to 1-bit monochrome output. Handle the case where AES padding is invalid. Changed XRef::getNumObjects to return the number of used entries, instead of the same value as returned by XRef::getSize(). Ignore bogus entries in the TrueType table directory instead of immediately giving up on the font. Fixed a bug in the radial shading code that could cause divide-by-zero errors. Tweaked the TrueType font fixup code to deal with an extra zero entry at the end of the loca table. Increased font cache sizes to improve performance. Tweaked the TrueType notdef kludge to skip the notdef glyph only if it was caused by a character for which a Unicode/MacRoman mapping could not be found. Added another font size sanity check, this time for Type 3 glyphs. Added initial support for optional content (layers) - no GUI yet. For CID fonts that specify the 'Adobe-Identity' or 'Adobe-UCS' collection, use an identity mapping for char code-to-Unicode conversion. Updated the error function to take a category argument, and to use GString::format instead of printf; added an error callback. The PDF spec claims that names are limited to 127 chars, but Distiller 8 will produce longer names, and Acrobat 8 will accept longer names -- Xpdf will now handle them, too. Change the Catalog code so it doesn't load the entire page tree at startup (this only helps the command line tools - the viewer scans all of the pages at startup). Clip opacity values to the range [0,1]. Handle glyph names of the form 'unixxxx' (similar to Ann, Axx, etc.). Resolution of rasterized pages in PostScript output was not being computed correctly (resulting in overly large images). Extend the mapUnknownCharNames config command to cover CID fonts. Zero-length segments in the middle of stroked paths were not being handled correctly -- they should be completely ignored, except for the special case of a zero-length path with round line caps. Various optimizations to the Splash rasterizer. Allow "Identity" and "Default" as the transfer function in soft masks. Tweaked the ToUnicode CMap parser to allow <00xx> char codes for 8-bit fonts. TextPage::clear() was not clearing the lists of underlines and links. Changed the CCITTFax decoder to correctly handle the interaction between the EndOfLine and EncodedByteAlign parameters. Fixed a bug where xpdf wouldn't go to a destination specified on the command line, if continuous mode was enabled (xpdf -cont file.pdf +foo). Fixed a bug in the FreeType interface code which was causing incorrect positioning/sizing of characters. Tweaked the FreeType interface code - use 'light' hinting with Type 1 fonts (because it generally looks better). Tweak the Windows font searching code to handle "Black" fonts. Fixed a bug in the PostScript-type function parser -- real numbers that start with a decimal point weren't being handled correctly. Changed the way filled-and-stroked text is handled -- use Splash to do both the fill and the stroke (rather than using the font ending to do the fill and Splash to do the stroke); also turn off stroke adjustment when drawing stroked text. Ignore generation numbers on compressed objects (to match Adobe's behavior). Changed the PostScript PageSize policy from 3 to 6 (choose next largest paper size, don't rescale). Check that the mask values for color key masked images are in range -- both Ghostscript and Distiller choke on the PostScript if invalid mask colors are specified. Fixed a bug in generic region decoding in the JBIG2 decoder. Fixed the lexer to handle large real numbers correctly. Pdftops wasn't correctly handling tiling patterns that use both fill and stroke operators. Report an error if the Size array in a sampled function includes any zeros. The PostScriptFunction.codeString field wasn't being initialized correctly. Invalid object streams were not being handled correctly. Check for loops in xref tables. Handle the case where a content stream ends after the 'ID' operator which starts inline image data. Check for invalid object streams (i.e., an object stream can't be inside another object stream. Add a recursion limit to the object parser - this avoids stack overflows with various sorts of damaged PDF files. Handle various parameter settings in the extended graphics state dictionary. An invalid document outline (missing fields) could cause a crash. Added an overprint preview mode (for CMYK output only). Correctly handle FitH/BH/V/BV link destinations that contain null values for positioning parameters. If the PDF file doesn't define a BaseURI, set one based on the location of the PDF file -- this allows relative links to be handled correctly. Use ResusableStreamDecode when generating Level 3 PostScript for an explicitly masked image. Tweak the Type 1 font parser to handle encodings with multiple characters on one line. Invert subtractive color components before passing them to the blending function. Fix an invalid array access in SplashOutputDev::setSoftMask() in CMYK mode. A PS interpreter may attempt to read past the end of a preloaded image, so we need to check for that. Fixed several overflow/uninit bugs in JBIG2Stream. Fix the CCITTFax decoder to correctly find end-of-file (RTC/EOFB) markers when the EndOfLine parameter is false. Don't limit the startxref offset to 10 digits - some PDF generators use extra leading zeros. Use the "DV" (default value) field in text annotations if the "V" (value) field is missing. Increase the number of digits printed for floating point numbers in PostScript output -- it was running into numerical accuracy problems on large pages. Fixed integer overflow bugs in Catalog.cc and GfxFont.cc. Zero-length tables in TrueType fonts should be treated as missing. ToUnicode CMaps map char codes to Unicode; .cidToUnicode files map CIDs to Unicode -- ToUnicodeCMaps were being handled incorrectly. Added the "psRasterResolution" and "psRasterMono" xpdfrc commands. Added code to FoFiTrueType to check for entries in the table directory with bogus tags -- this handles the case where the number of tables given in the header is too high. Negative shift values in the PostScript bitshift operator were being handled incorrectly. GfxICCBasedColorSpace was not correctly bounds-checking the number of components. Check SampledFunction input values for NaNs. Fix a divide-by-zero when the page width or height is zero. Fix a bug positioning text in PostScript output - if the last char in a string has an incorrect width in the PDF font object, that messes up the total string width, so we have to position individual chars. In PostScript output, if CID font substitution fails, drop all text in that font. Handle PDF files that set the stream/string decryption filters to Identity (i.e., no encryption). Avoid passing a zero font size to FreeType. Tweak raw mode in the text extractor to handle words on the same line drawn in the wrong order. Pdftops was generating a singular transform matrix for annotations whose bounding boxes had zero width or height. Handle embedded OpenType CFF fonts with CIDToGIDMaps. Remove the old kludge from PSOutputDev that was converting char 32 from ".notdef" to "space". Allow CCITTFax images to be more than 32k pixels wide. Modified the CMap parser to handle usecmap with Identity-H/V. Added some parameter checking in the JPX decoder. Added checks for infinite loops in PDF objects - for color spaces, functions, optional content, and outline items. Add support for mouse button bindings up to button 32 (old limit was 7). Fixed a bug in the decryption code for revision 3 with keyLength < 16 -- the owner password was not being handled correctly. [Thanks to Matthias Franz.] Optimize SampledFunction: pull index computation code out of the transform function; cache the last transform. Tweaked the font naming algorithm in PSOutputDev. Treat mirrored (as opposed to rotated) text the same as upright text in pdftotext. Fixed buffer overflows in Splash and SplashBitmap. Check for bogus character codes (e.g., ) in ToUnicode CMaps. The radial shading code (in both Gfx.cc and PSOutputDev.cc) was not computing the s bounds properly. Drop empty subpaths in clip and fill (but not stroke) operations - this can significantly speed up clip performance in the weird case where a PDF file does " re m h W n". Added code to FoFiTrueType to check for an invalid loca format field in the head table. The axial shading code (in Gfx.cc, but not PSOutputDev.cc) was not computing the incremental polygon vertices correctly. Set the character width in TextOutputDev to something sensible for vertical fonts. Added basic support to the text extractor for vertical writing mode. The non-interactive tools (pdftotext, pdftops) now free Page objects after using them, avoiding performance problems with pages that have huge resource dictionaries. Check for line dash arrays like [0], and draw nothing at all (to match Acrobat's behavior). Add a sanity check for the ascent/descent values in FontDescriptors. Single-point paths with a line dash were causing a crash. Correctly handle Level 3 PostScript output with masked images inside patterns. Tweaked the xref repair code so that it runs if the catalog is messed up (in addition to running if the xref table is damaged). If Indexed color space tables (streams or strings) are too small, reduce the max index instead of throwing away the color space. Change the CMap parser to allocate memory only when it sees a mapping, not when it sees a 'codespacerange' declaration -- this avoids allocating huge amounts of memory for CMaps with large, unused codespaceranges. In monochrome mode, treat lines with width <= 1 as hairlines (to match Acrobat's behavior). Cache the last transform for PostScript-type functions. Added the "-rawdates" option to pdfinfo. Optimized ImageStream::getLine(). Fixed the Hue, Saturation, Color, and Luminosity blend functions to match Adobe's spec. Fixed the non-isolated group compositing computation. Skip extraneous unused data at the end of JBIG2 segments. Change the algorithm that stroke/fill adjustment uses so that the edges of adjacent strokes/fills line up. Do stroke adjustment on end caps when cap style is butt or projecting. Fixed a security hole: Gfx.parser was not being initialized to NULL. Fixed a security hole: integer bounds check in the Type 1 encoding parser in FoFiType1.cc. If an embedded font object is invalid or non-existent, do font substitution (same as if there were no embedded font). TextOutputDev was reusing an old font in the case where the font changed but the font size and character positioning stayed the same. When starting a transparency group, copy the fill/stroke colors from the graphics state. Tweaked the fixed-point code. When a TrueType font is declared resident (with a psFont command), don't munge the encoding. Look for URIs starting with "www." and treat them as absolute "http:" URIs, not as relative URIs (to match Adobe's behavior). Added code to FoFiTrueType to check for a zero-entry cmap table. Tweaked the font substitution code to do a better job of scaling the substituted font. Require at least two splits in the axial shading color bisection. Optimized JBIG2Stream::readGenericBitmap(). JPXStream wasn't correctly handling row padding for images with fewer than 8 bits per component. Optimized the ToUnicode CMap parser. Added a "whole words only" option to text searches. Check for valid component parameters in the DCT decoder. Implement embedding of external 16-bit fonts (without subsetting) in PostScript output. Added the minLineWidth xpdfrc command. Added warning messages for font substitutions. xpdf-3.03/aclocal.m40000644000076400007640000002424311622305345013560 0ustar dereknderekn# <<< smr.m4 from smr_macros 0.2.4 >>> dnl ####################### -*- Mode: M4 -*- ########################### dnl smr.m4 -- dnl dnl Copyright (C) 1999 Matthew D. Langston dnl Copyright (C) 1998 Steve Robbins dnl dnl This file is free software; you can redistribute it and/or modify it dnl under the terms of the GNU General Public License as published by dnl the Free Software Foundation; either version 2 of the License, or dnl (at your option) any later version. dnl dnl This file is distributed in the hope that it will be useful, but dnl WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU dnl General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this file; if not, write to: dnl dnl Free Software Foundation, Inc. dnl Suite 330 dnl 59 Temple Place dnl Boston, MA 02111-1307, USA. dnl #################################################################### dnl NOTE: The macros in this file are extensively documented in the dnl accompanying `smr_macros.texi' Texinfo file. Please see the dnl Texinfo documentation for the definitive specification of how dnl these macros are supposed to work. If the macros work dnl differently than the Texinfo documentation says they should, dnl then the macros (and not the Texinfo documentation) has the dnl bug(s). dnl This is a convenient macro which translates illegal characters for dnl bourne shell variables into legal characters. It has the same dnl functionality as sed 'y%./+-:%__p__%'. AC_DEFUN([smr_safe_translation], [patsubst(patsubst([$1], [+], [p]), [./-:], [_])]) AC_DEFUN(smr_SWITCH, [ dnl Define convenient aliases for the arguments since there are so dnl many of them and I keep confusing myself whenever I have to edit dnl this macro. pushdef([smr_name], $1) pushdef([smr_help_string], $2) pushdef([smr_default], $3) pushdef([smr_yes_define], $4) pushdef([smr_no_define], $5) dnl Do some sanity checking of the arguments. ifelse([regexp(smr_default, [^\(yes\|no\)$])], -1, [AC_MSG_ERROR($0: third arg must be either yes or no)]) dnl Create the help string pushdef([smr_lhs], [--ifelse(smr_default, yes, disable, enable)-smr_name])dnl pushdef([smr_rhs], [ifelse(smr_default, yes, disable, enable) smr_help_string (default is smr_default)])dnl dnl Add the option to `configure --help'. We don't need to supply the dnl 4th argument to AC_ARG_ENABLE (i.e. the code to set the default dnl value) because that is done below by AC_CACHE_CHECK. AC_ARG_ENABLE([smr_name], AC_HELP_STRING([smr_lhs], [smr_rhs]), smr_cv_enable_[]smr_name=$enableval) dnl We cache the result so that the user doesn't have to remember dnl which flags they passed to `configure'. AC_CACHE_CHECK([whether to enable smr_help_string], smr_cv_enable_[]smr_name, smr_cv_enable_[]smr_name=smr_default) ifelse(smr_yes_define, , , test x"[$]smr_cv_enable_[]smr_name" = xyes && AC_DEFINE(smr_yes_define)) ifelse(smr_no_define, , , test x"[$]smr_cv_enable_[]smr_name" = xno && AC_DEFINE(smr_no_define)) dnl Sanity check the value assigned to smr_cv_enable_$1 to force it to dnl be either `yes' or `no'. if test ! x"[$]smr_cv_enable_[]smr_name" = xyes; then if test ! x"[$]smr_cv_enable_[]smr_name" = xno; then AC_MSG_ERROR([smr_lhs must be either yes or no]) fi fi popdef([smr_name]) popdef([smr_help_string]) popdef([smr_default]) popdef([smr_yes_define]) popdef([smr_no_define]) popdef([smr_lhs]) popdef([smr_rhs]) ]) AC_DEFUN(smr_ARG_WITHLIB, [ dnl Define convenient aliases for the arguments since there are so dnl many of them and I keep confusing myself whenever I have to edit dnl this macro. pushdef([smr_name], $1) pushdef([smr_libname], ifelse($2, , smr_name, $2)) pushdef([smr_help_string], $3) pushdef([smr_safe_name], smr_safe_translation(smr_name)) dnl Add the option to `configure --help'. We don't need to supply the dnl 4th argument to AC_ARG_WITH (i.e. the code to set the default dnl value) because that is done below by AC_CACHE_CHECK. AC_ARG_WITH(smr_safe_name-library, AC_HELP_STRING([--with-smr_safe_name-library[[=PATH]]], [use smr_name library ifelse(smr_help_string, , , (smr_help_string))]), smr_cv_with_[]smr_safe_name[]_library=$withval) dnl We cache the result so that the user doesn't have to remember dnl which flags they passed to `configure'. AC_CACHE_CHECK([whether to use smr_name library], smr_cv_with_[]smr_safe_name[]_library, smr_cv_with_[]smr_safe_name[]_library=maybe) case x"[$]smr_cv_with_[]smr_safe_name[]_library" in xyes | xmaybe) smr_safe_name[]_LIBS="-l[]smr_libname" with_[]smr_safe_name=[$]smr_cv_with_[]smr_safe_name[]_library ;; xno) smr_safe_name[]_LIBS= with_[]smr_safe_name=no ;; *) if test -f "[$]smr_cv_with_[]smr_safe_name[]_library"; then smr_safe_name[]_LIBS=[$]smr_cv_with_[]smr_safe_name[]_library elif test -d "[$]smr_cv_with_[]smr_safe_name[]_library"; then smr_safe_name[]_LIBS="-L[$]smr_cv_with_[]smr_safe_name[]_library -l[]smr_libname" else AC_MSG_ERROR([argument must be boolean, file, or directory]) fi with_[]smr_safe_name=yes ;; esac popdef([smr_name]) popdef([smr_libname]) popdef([smr_help_string]) popdef([smr_safe_name]) ]) AC_DEFUN(smr_ARG_WITHINCLUDES, [ dnl Define convenient aliases for the arguments since there are so dnl many of them and I keep confusing myself whenever I have to edit dnl this macro. pushdef([smr_name], $1) pushdef([smr_header], $2) pushdef([smr_extra_flags], $3) pushdef([smr_safe_name], smr_safe_translation(smr_name)) dnl Add the option to `configure --help'. We don't need to supply the dnl 4th argument to AC_ARG_WITH (i.e. the code to set the default dnl value) because that is done below by AC_CACHE_CHECK. AC_ARG_WITH(smr_safe_name-includes, AC_HELP_STRING([--with-smr_safe_name-includes[[=DIR]]], [set directory for smr_name headers]), smr_cv_with_[]smr_safe_name[]_includes=$withval) dnl We cache the result so that the user doesn't have to remember dnl which flags they passed to `configure'. AC_CACHE_CHECK([where to find the smr_name header files], smr_cv_with_[]smr_safe_name[]_includes, smr_cv_with_[]smr_safe_name[]_includes=) if test ! x"[$]smr_cv_with_[]smr_safe_name[]_includes" = x; then if test -d "[$]smr_cv_with_[]smr_safe_name[]_includes"; then smr_safe_name[]_CFLAGS="-I[$]smr_cv_with_[]smr_safe_name[]_includes" else AC_MSG_ERROR([argument must be a directory]) fi else smr_safe_name[]_CFLAGS= fi dnl This bit of logic comes from the autoconf AC_PROG_CC macro. We dnl need to put the given include directory into CPPFLAGS temporarily, dnl but then restore CPPFLAGS to its old value. smr_test_CPPFLAGS="${CPPFLAGS+set}" smr_save_CPPFLAGS="$CPPFLAGS" CPPFLAGS="$CPPFLAGS [$]smr_safe_name[]_CFLAGS smr_extra_flags" dnl If the header file smr_header exists, then define dnl HAVE_[]smr_header (in all capitals). AC_CHECK_HEADERS([smr_header], smr_have_[]smr_safe_name[]_header=yes, smr_have_[]smr_safe_name[]_header=no) if test x"$smr_test_CPPFLAGS" = xset; then CPPFLAGS=$smr_save_CPPFLAGS else unset CPPFLAGS fi popdef([smr_name]) popdef([smr_header]) popdef([smr_extra_flags]) popdef([smr_safe_name]) ]) AC_DEFUN(smr_CHECK_LIB, [ dnl Define convenient aliases for the arguments since there are so dnl many of them and I keep confusing myself whenever I have to edit dnl this macro. pushdef([smr_name], $1) pushdef([smr_libname], ifelse($2, , smr_name, $2)) pushdef([smr_help_string], $3) pushdef([smr_function], $4) pushdef([smr_header], $5) pushdef([smr_extra_libs], $6) pushdef([smr_extra_flags], $7) pushdef([smr_prototype], $8) pushdef([smr_safe_name], smr_safe_translation(smr_name)) dnl Give the user (via "configure --help") an interface to specify dnl whether we should use the library or not, and possibly where we dnl should find it. smr_ARG_WITHLIB([smr_name], [smr_libname], [smr_help_string]) if test ! x"$with_[]smr_safe_name" = xno; then # If we got this far, then the user didn't explicitly ask not to use # the library. dnl If the caller of smr_CHECK_LIB specified a header file for this dnl library, then give the user (via "configure --help") an dnl interface to specify where this header file can be found (if it dnl isn't found by the compiler by default). ifelse(smr_header, , , [smr_ARG_WITHINCLUDES(smr_name, smr_header, smr_extra_flags)]) # We need only look for the library if the header has been found # (or no header is needed). if test [$]smr_have_[]smr_safe_name[]_header != no; then AC_CHECK_LIB(smr_libname, smr_function, smr_have_[]smr_safe_name[]_library=yes, smr_have_[]smr_safe_name[]_library=no, [$]smr_safe_name[]_CFLAGS [smr_extra_flags] [$]smr_safe_name[]_LIBS [smr_extra_libs], [ifelse(smr_prototype, , , [[#]include ])], smr_prototype) fi if test x"[$]smr_have_[]smr_safe_name[]_library" = xyes; then AC_MSG_RESULT([using smr_name library]) else smr_safe_name[]_LIBS= smr_safe_name[]_CFLAGS= if test x"$with_[]smr_safe_name" = xmaybe; then AC_MSG_RESULT([not using smr_name library]) else AC_MSG_WARN([requested smr_name library not found!]) fi fi fi popdef([smr_name]) popdef([smr_libname]) popdef([smr_help_string]) popdef([smr_function]) popdef([smr_header]) popdef([smr_extra_libs]) popdef([smr_extra_flags]) popdef([smr_prototype]) popdef([smr_safe_name]) ]) xpdf-3.03/COPYING30000644000076400007640000010451311622305345013035 0ustar dereknderekn GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . xpdf-3.03/Makefile.in0000644000076400007640000000765511622305344013774 0ustar dereknderekn#======================================================================== # # Main xpdf Makefile. # # Copyright 1996-2003 Glyph & Cog, LLC # #======================================================================== SHELL = /bin/sh DESTDIR = prefix = @prefix@ exec_prefix = @exec_prefix@ srcdir = @srcdir@ INSTALL = @INSTALL@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_DATA = @INSTALL_DATA@ EXE = @EXE@ all: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) @XPDF_TARGET@ all-no-x: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) all-no-x xpdf: dummy cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) xpdf$(EXE) pdftops: dummy cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdftops$(EXE) pdftotext: dummy cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdftotext$(EXE) pdfinfo: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdfinfo$(EXE) pdffonts: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdffonts$(EXE) pdfdetach: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdfdetach$(EXE) pdftoppm: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdftoppm$(EXE) pdfimages: cd goo; $(MAKE) cd @UP_DIR@fofi; $(MAKE) cd @UP_DIR@splash; $(MAKE) cd @UP_DIR@xpdf; $(MAKE) pdfimages$(EXE) dummy: install: dummy -mkdir -p $(DESTDIR)@bindir@ @X@ $(INSTALL_PROGRAM) xpdf/xpdf$(EXE) $(DESTDIR)@bindir@/xpdf$(EXE) $(INSTALL_PROGRAM) xpdf/pdftops$(EXE) $(DESTDIR)@bindir@/pdftops$(EXE) $(INSTALL_PROGRAM) xpdf/pdftotext$(EXE) $(DESTDIR)@bindir@/pdftotext$(EXE) $(INSTALL_PROGRAM) xpdf/pdfinfo$(EXE) $(DESTDIR)@bindir@/pdfinfo$(EXE) $(INSTALL_PROGRAM) xpdf/pdffonts$(EXE) $(DESTDIR)@bindir@/pdffonts$(EXE) $(INSTALL_PROGRAM) xpdf/pdfdetach$(EXE) $(DESTDIR)@bindir@/pdfdetach$(EXE) @X@ $(INSTALL_PROGRAM) xpdf/pdftoppm$(EXE) $(DESTDIR)@bindir@/pdftoppm$(EXE) $(INSTALL_PROGRAM) xpdf/pdfimages$(EXE) $(DESTDIR)@bindir@/pdfimages$(EXE) -mkdir -p $(DESTDIR)@mandir@/man1 @X@ $(INSTALL_DATA) $(srcdir)/doc/xpdf.1 $(DESTDIR)@mandir@/man1/xpdf.1 $(INSTALL_DATA) $(srcdir)/doc/pdftops.1 $(DESTDIR)@mandir@/man1/pdftops.1 $(INSTALL_DATA) $(srcdir)/doc/pdftotext.1 $(DESTDIR)@mandir@/man1/pdftotext.1 $(INSTALL_DATA) $(srcdir)/doc/pdfinfo.1 $(DESTDIR)@mandir@/man1/pdfinfo.1 $(INSTALL_DATA) $(srcdir)/doc/pdffonts.1 $(DESTDIR)@mandir@/man1/pdffonts.1 $(INSTALL_DATA) $(srcdir)/doc/pdfdetach.1 $(DESTDIR)@mandir@/man1/pdfdetach.1 @X@ $(INSTALL_DATA) $(srcdir)/doc/pdftoppm.1 $(DESTDIR)@mandir@/man1/pdftoppm.1 $(INSTALL_DATA) $(srcdir)/doc/pdfimages.1 $(DESTDIR)@mandir@/man1/pdfimages.1 -mkdir -p $(DESTDIR)@mandir@/man5 $(INSTALL_DATA) $(srcdir)/doc/xpdfrc.5 $(DESTDIR)@mandir@/man5/xpdfrc.5 -mkdir -p $(DESTDIR)@sysconfdir@ @if test ! -f $(DESTDIR)@sysconfdir@/xpdfrc; then \ echo "$(INSTALL_DATA) $(srcdir)/doc/sample-xpdfrc $(DESTDIR)@sysconfdir@/xpdfrc"; \ $(INSTALL_DATA) $(srcdir)/doc/sample-xpdfrc $(DESTDIR)@sysconfdir@/xpdfrc; \ else \ echo "# not overwriting the existing $(DESTDIR)@sysconfdir@/xpdfrc"; \ fi clean: -cd goo; $(MAKE) clean -cd @UP_DIR@fofi; $(MAKE) clean -cd @UP_DIR@splash; $(MAKE) clean -cd @UP_DIR@xpdf; $(MAKE) clean distclean: clean rm -f config.log config.status config.cache rm -f aconf.h rm -f Makefile goo/Makefile xpdf/Makefile rm -f goo/Makefile.dep fofi/Makefile.dep splash/Makefile.dep xpdf/Makefile.dep rm -f goo/Makefile.in.bak fofi/Makefile.in.bak splash/Makefile.in.bak xpdf/Makefile.in.bak touch goo/Makefile.dep touch fofi/Makefile.dep touch splash/Makefile.dep touch xpdf/Makefile.dep depend: cd goo; $(MAKE) depend cd @UP_DIR@fofi; $(MAKE) depend cd @UP_DIR@splash; $(MAKE) depend cd @UP_DIR@xpdf; $(MAKE) depend xpdf-3.03/README0000644000076400007640000003544411622305345012605 0ustar derekndereknXpdf ==== version 3.03 2011-aug-15 The Xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. Email: derekn@foolabs.com WWW: http://www.foolabs.com/xpdf/ The PDF data structures, operators, and specification are copyright 1985-2006 Adobe Systems Inc. What is Xpdf? ------------- Xpdf is an open source viewer for Portable Document Format (PDF) files. (These are also sometimes also called 'Acrobat' files, from the name of Adobe's PDF software.) The Xpdf project also includes a PDF text extractor, PDF-to-PostScript converter, and various other utilities. Xpdf runs under the X Window System on UNIX, VMS, and OS/2. The non-X components (pdftops, pdftotext, etc.) also run on Windows and Mac OSX systems and should run on pretty much any system with a decent C++ compiler. Xpdf will run on 32-bit and 64-bit machines. License & Distribution ---------------------- Xpdf is licensed under the GNU General Pulbic License (GPL), version 2 or 3. This means that you can distribute derivatives of Xpdf under any of the following: - GPL v2 only - GPL v3 only - GPL v2 or v3 The Xpdf source package includes the text of both GPL versions: COPYING for GPL v2, COPYING3 for GPL v3. Please note that Xpdf is NOT licensed under "any later version" of the GPL, as I have no idea what those versions will look like. If you are redistributing unmodified copies of Xpdf (or any of the Xpdf tools) in binary form, you need to include all of the documentation: README, man pages (or help files), COPYING, and COPYING3. If you want to incorporate the Xpdf source code into another program (or create a modified version of Xpdf), and you are distributing that program, you have two options: release your program under the GPL (v2 and/or v3), or purchase a commercial Xpdf source license. If you're interested in commercial licensing, please see the Glyph & Cog web site: http://www.glyphandcog.com/ Compatibility ------------- Xpdf is developed and tested on Linux. In addition, it has been compiled by others on Solaris, AIX, HP-UX, Digital Unix, Irix, and numerous other Unix implementations, as well as VMS and OS/2. It should work on pretty much any system which runs X11 and has Unix-like libraries. You'll need ANSI C++ and C compilers to compile it. The non-X components of Xpdf (pdftops, pdftotext, pdfinfo, pdffonts, pdfdetach, pdftoppm, and pdfimages) can also be compiled on Windows and Mac OSX systems. See the Xpdf web page for details. If you compile Xpdf for a system not listed on the web page, please let me know. If you're willing to make your binary available by ftp or on the web, I'll be happy to add a link from the Xpdf web page. I have decided not to host any binaries I didn't compile myself (for disk space and support reasons). If you can't get Xpdf to compile on your system, send me email and I'll try to help. Xpdf has been ported to the Acorn, Amiga, BeOS, and EPOC. See the Xpdf web page for links. Getting Xpdf ------------ The latest version is available from: http://www.foolabs.com/xpdf/ or: ftp://ftp.foolabs.com/pub/xpdf/ Source code and several precompiled executables are available. Announcements of new versions are posted to comp.text.pdf and emailed to a list of people. If you'd like to receive email notification of new versions, just let me know. Running Xpdf ------------ To run xpdf, simply type: xpdf file.pdf To generate a PostScript file, hit the "print" button in xpdf, or run pdftops: pdftops file.pdf To generate a plain text file, run pdftotext: pdftotext file.pdf There are five additional utilities (which are fully described in their man pages): pdfinfo -- dumps a PDF file's Info dictionary (plus some other useful information) pdffonts -- lists the fonts used in a PDF file along with various information for each font pdfdetach -- lists or extracts embedded files (attachments) from a PDF file pdftoppm -- converts a PDF file to a series of PPM/PGM/PBM-format bitmaps pdfimages -- extracts the images from a PDF file Command line options and many other details are described in the man pages (xpdf(1), etc.) and the VMS help files (xpdf.hlp, etc.). All of these utilities read an optional configuration file: see the xpdfrc(5) man page. Upgrading from Xpdf 3.02 (and earlier) -------------------------------------- The font configuration system has been changed. Previous versions used mostly separate commands to configure fonts for display and for PostScript output. As of 3.03, configuration options that make sense for both display and PS output have been unified. The following xpdfrc commands have been removed: * displayFontT1, displayFontTT: replaced with fontFile * displayNamedCIDFontT1, displayNamedCIDFontTT: replaced with fontFile * displayCIDFontT1, displayCIDFontTT: replaced with fontFileCC * psFont: replaced with psResidentFont * psNamedFont16: replaced with psResidentFont16 * psFont16: replaced with psResidentFontCC See the xpdfrc(5) man page for more information on the new commands. Pdftops will now embed external 16-bit fonts (configured with the fontFileCC command) when the PDF file refers to a non-embedded font. It does not do any subsetting (yet), so the resulting PS files will be large. Compiling Xpdf -------------- See the separate file, INSTALL. Bugs ---- If you find a bug in Xpdf, i.e., if it prints an error message, crashes, or incorrectly displays a document, and you don't see that bug listed here, please send me email, with a pointer (URL, ftp site, etc.) to the PDF file. Acknowledgments --------------- Thanks to: * Patrick Voigt for help with the remote server code. * Patrick Moreau, Martin P.J. Zinser, and David Mathog for the VMS port. * David Boldt and Rick Rodgers for sample man pages. * Brendan Miller for the icon idea. * Olly Betts for help testing pdftotext. * Peter Ganten for the OS/2 port. * Michael Richmond for the Win32 port of pdftops and pdftotext and the xpdf/cygwin/XFree86 build instructions. * Frank M. Siegert for improvements in the PostScript code. * Leo Smiers for the decryption patches. * Rainer Menzner for creating t1lib, and for helping me adapt it to xpdf. * Pine Tree Systems A/S for funding the OPI and EPS support in pdftops. * Easy Software Products for funding several improvements to the PostScript output code. * Tom Kacvinsky for help with FreeType and for being my interface to the FreeType team. * Theppitak Karoonboonyanan for help with Thai support. * Leonard Rosenthol for help and contributions on a bunch of things. * Alexandros Diamantidis and Maria Adaloglou for help with Greek support. * Lawrence Lai for help with the CJK Unicode maps. Various people have contributed modifications made for use by the pdftex project: * Han The Thanh * Martin Schr鰀er of ArtCom GmbH References ---------- Adobe Systems Inc., _PDF Reference, sixth edition: Adobe Portable Document Format version 1.7_. http://www.adobe.com/devnet/pdf/pdf_reference.html [The manual for PDF version 1.7.] Adobe Systems Inc., "Errata for the PDF Reference, sixth edition, version 1.7", October 16, 2006. http://www.adobe.com/devnet/pdf/pdf_reference.html [The errata for the PDF 1.7 spec.] Adobe Systems Inc., _PostScript Language Reference_, 3rd ed. Addison-Wesley, 1999, ISBN 0-201-37922-8. [The official PostScript manual.] Adobe Systems, Inc., _The Type 42 Font Format Specification_, Adobe Developer Support Technical Specification #5012. 1998. http://partners.adobe.com/asn/developer/pdfs/tn/5012.Type42_Spec.pdf [Type 42 is the format used to embed TrueType fonts in PostScript files.] Adobe Systems, Inc., _Adobe CMap and CIDFont Files Specification_, Adobe Developer Support Technical Specification #5014. 1995. http://www.adobe.com/supportservice/devrelations/PDFS/TN/5014.CIDFont_Spec.pdf [CMap file format needed for Japanese and Chinese font support.] Adobe Systems, Inc., _Adobe-Japan1-4 Character Collection for CID-Keyed Fonts_, Adobe Developer Support Technical Note #5078. 2000. http://partners.adobe.com/asn/developer/PDFS/TN/5078.CID_Glyph.pdf [The Adobe Japanese character set.] Adobe Systems, Inc., _Adobe-GB1-4 Character Collection for CID-Keyed Fonts_, Adobe Developer Support Technical Note #5079. 2000. http://partners.adobe.com/asn/developer/pdfs/tn/5079.Adobe-GB1-4.pdf [The Adobe Chinese GB (simplified) character set.] Adobe Systems, Inc., _Adobe-CNS1-3 Character Collection for CID-Keyed Fonts_, Adobe Developer Support Technical Note #5080. 2000. http://partners.adobe.com/asn/developer/PDFS/TN/5080.CNS_CharColl.pdf [The Adobe Chinese CNS (traditional) character set.] Adobe Systems Inc., _Supporting the DCT Filters in PostScript Level 2_, Adobe Developer Support Technical Note #5116. 1992. http://www.adobe.com/supportservice/devrelations/PDFS/TN/5116.PS2_DCT.PDF [Description of the DCTDecode filter parameters.] Adobe Systems Inc., _Open Prepress Interface (OPI) Specification - Version 2.0_, Adobe Developer Support Technical Note #5660. 2000. http://partners.adobe.com/asn/developer/PDFS/TN/5660.OPI_2.0.pdf Adobe Systems Inc., CMap files. ftp://ftp.oreilly.com/pub/examples/nutshell/cjkv/adobe/ [The actual CMap files for the 16-bit CJK encodings.] Adobe Systems Inc., Unicode glyph lists. http://partners.adobe.com/asn/developer/type/unicodegn.html http://partners.adobe.com/asn/developer/type/glyphlist.txt http://partners.adobe.com/asn/developer/type/corporateuse.txt http://partners.adobe.com/asn/developer/type/zapfdingbats.txt [Mappings between character names to Unicode.] Adobe Systems Inc., OpenType Specification v. 1.4. http://partners.adobe.com/public/developer/opentype/index_spec.html [The OpenType font format spec.] Aldus Corp., _OPI: Open Prepress Interface Specification 1.3_. 1993. http://partners.adobe.com/asn/developer/PDFS/TN/OPI_13.pdf Anonymous, RC4 source code. ftp://ftp.ox.ac.uk/pub/crypto/misc/rc4.tar.gz ftp://idea.sec.dsi.unimi.it/pub/crypt/code/rc4.tar.gz [This is the algorithm used to encrypt PDF files.] T. Boutell, et al., "PNG (Portable Network Graphics) Specification, Version 1.0". RFC 2083. [PDF uses the PNG filter algorithms.] CCITT, "Information Technology - Digital Compression and Coding of Continuous-tone Still Images - Requirements and Guidelines", CCITT Recommendation T.81. http://www.w3.org/Graphics/JPEG/ [The official JPEG spec.] A. Chernov, "Registration of a Cyrillic Character Set". RFC 1489. [Documentation for the KOI8-R Cyrillic encoding.] Roman Czyborra, "The ISO 8859 Alphabet Soup". http://czyborra.com/charsets/iso8859.html [Documentation on the various ISO 859 encodings.] L. Peter Deutsch, "ZLIB Compressed Data Format Specification version 3.3". RFC 1950. [Information on the general format used in FlateDecode streams.] L. Peter Deutsch, "DEFLATE Compressed Data Format Specification version 1.3". RFC 1951. [The definition of the compression algorithm used in FlateDecode streams.] Morris Dworkin, "Recommendation for Block Cipher Modes of Operation", National Institute of Standards, NIST Special Publication 800-38A, 2001. [The cipher block chaining (CBC) mode used with AES in PDF files.] Federal Information Processing Standards Publication 197 (FIPS PUBS 197), "Advanced Encryption Standard (AES)", November 26, 2001. [AES encryption, used in PDF 1.6.] Jim Flowers, "X Logical Font Description Conventions", Version 1.5, X Consortium Standard, X Version 11, Release 6.1. ftp://ftp.x.org/pub/R6.1/xc/doc/hardcopy/XLFD/xlfd.PS.Z [The official specification of X font descriptors, including font transformation matrices.] Foley, van Dam, Feiner, and Hughes, _Computer Graphics: Principles and Practice_, 2nd ed. Addison-Wesley, 1990, ISBN 0-201-12110-7. [Colorspace conversion functions, Bezier spline math.] Robert L. Hummel, _Programmer's Technical Reference: Data and Fax Communications_. Ziff-Davis Press, 1993, ISBN 1-56276-077-7. [CCITT Group 3 and 4 fax decoding.] ISO/IEC, _Information technology -- Lossy/lossless coding of bi-level images_. ISO/IEC 14492, First edition (2001-12-15). http://webstore.ansi.org/ [The official JBIG2 standard. The final draft of this spec is available from http://www.jpeg.org/jbighomepage.html.] ISO/IEC, _Information technology -- JPEG 2000 image coding system -- Part 1: Core coding system_. ISO/IEC 15444-1, First edition (2000-12-15). http://webstore.ansi.org/ [The official JPEG 2000 standard. The final committee draft of this spec is available from http://www.jpeg.org/JPEG2000.html, but there were changes made to the bitstream format between that draft and the published spec.] ITU, "Standardization of Group 3 facsimile terminals for document transmission", ITU-T Recommendation T.4, 1999. ITU, "Facsimile coding schemes and coding control functions for Group 4 facsimile apparatus", ITU-T Recommendation T.6, 1993. http://www.itu.int/ [The official Group 3 and 4 fax standards - used by the CCITTFaxDecode stream, as well as the JBIG2Decode stream.] B. Kaliski, "PKCS #5: Password-Based Cryptography Specification, Version 2.0". RFC 2898. [Defines the padding scheme used with AES encryption in PDF files.] Christoph Loeffler, Adriaan Ligtenberg, George S. Moschytz, "Practical Fast 1-D DCT Algorithms with 11 Multiplications". IEEE Intl. Conf. on Acoustics, Speech & Signal Processing, 1989, 988-991. [The fast IDCT algorithm used in the DCTDecode filter.] Microsoft, _TrueType 1.0 Font Files_, rev. 1.66. 1995. http://www.microsoft.com/typography/tt/tt.htm [The TrueType font spec (in MS Word format, naturally).] V. Ostromoukhov, R.D. Hersch, "Stochastic Clustered-Dot Dithering", Conf. Color Imaging: Device-Independent Color, Color Hardcopy, and Graphic Arts IV, 1999, SPIE Vol. 3648, 496-505. http://diwww.epfl.ch/w3lsp/publications/colour/scd.html [The stochastic dithering algorithm used in Xpdf.] P. Peterlin, "ISO 8859-2 (Latin 2) Resources". http://sizif.mf.uni-lj.si/linux/cee/iso8859-2.html [This is a web page with all sorts of useful Latin-2 character set and font information.] Charles Poynton, "Color FAQ". http://www.inforamp.net/~poynton/ColorFAQ.html [The mapping from the CIE 1931 (XYZ) color space to RGB.] R. Rivest, "The MD5 Message-Digest Algorithm". RFC 1321. [MD5 is used in PDF document encryption.] Thai Industrial Standard, "Standard for Thai Character Codes for Computers", TIS-620-2533 (1990). http://www.nectec.or.th/it-standards/std620/std620.htm [The TIS-620 Thai encoding.] Unicode Consortium, "Unicode Home Page". http://www.unicode.org/ [Online copy of the Unicode spec.] W3C Recommendation, "PNG (Portable Network Graphics) Specification Version 1.0". http://www.w3.org/Graphics/PNG/ [Defines the PNG image predictor.] Gregory K. Wallace, "The JPEG Still Picture Compression Standard". ftp://ftp.uu.net/graphics/jpeg/wallace.ps.gz [Good description of the JPEG standard. Also published in CACM, April 1991, and submitted to IEEE Transactions on Consumer Electronics.] F. Yergeau, "UTF-8, a transformation format of ISO 10646". RFC 2279. [A commonly used Unicode encoding.] xpdf-3.03/doc/0000755000076400007640000000000011622305345012460 5ustar derekndereknxpdf-3.03/doc/pdftotext.hlp0000644000076400007640000001057311622305345015214 0ustar dereknderekn! Generated automatically by mantohlp 1 pdftotext pdftotext - Portable Document Format (PDF) to text converter pdftotext [options] [PDF-file [text-file]] Pdftotext converts Portable Document Format (PDF) files to plain text. Pdftotext reads the PDF file, PDF-file, and writes a text file, text- file. If text-file is not specified, pdftotext converts file.pdf to file.txt. If text-file is '-', the text is sent to stdout. () 2 ONFIGURATION_FIL Pdftotext reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftotext is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to convert. -l number Specifies the last page to convert. -layout Maintain (as best as possible) the original physical layout of the text. The default is to 'undo' physical layout (columns, hyphenation, etc.) and output the text in reading order. -fixed number Assume fixed-pitch (or tabular) text, with the specified charac- ter width (in points). This forces physical layout mode. -raw Keep the text in content stream order. This is a hack which often "undoes" column formatting, etc. Use of raw mode is no longer recommended. -htmlmeta Generate a simple HTML file, including the meta information. This simply wraps the text in
 and 
and prepends the meta headers. -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). The encoding name is case-sensitive. This defaults to "Latin1" (which is a built-in encoding). [config file: textEncoding] -eol unix | dos | mac Sets the end-of-line convention to use for text output. [config file: textEOL] -nopgbrk Don't insert page breaks (form feed characters) between pages. [config file: textPageBreaks] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 BUGS Some PDF files contain fonts whose encodings have been mangled beyond recognition. There is no way (short of OCR) to extract text from these files. () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdftotext software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/xpdf.10000644000076400007640000005472011622305345013513 0ustar dereknderekn.\" Copyright 1996-2011 Glyph & Cog, LLC .TH xpdf 1 "15 August 2011" .SH NAME xpdf \- Portable Document Format (PDF) file viewer for X (version 3.03) .SH SYNOPSIS .B xpdf [options] .RI [ PDF-file .RI [ page " | +" dest ]] .SH DESCRIPTION .B Xpdf is a viewer for Portable Document Format (PDF) files. (These are also sometimes also called \'Acrobat' files, from the name of Adobe's PDF software.) Xpdf runs under the X Window System on UNIX, VMS, and OS/2. .PP To run xpdf, simply type: .PP .RS xpdf file.pdf .RE .PP where .I file.pdf is your PDF file. The file name can be followed by a number specifying the page which should be displayed first, e.g.: .PP .RS xpdf file.pdf 18 .RE .PP You can also give a named destination, prefixed with \'+' in place of the page number. (This is only useful with PDF files that provide named destination targets.) .PP You can also start xpdf without opening any files: .PP .RS xpdf .RE .SH CONFIGURATION FILE Xpdf reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when xpdf is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands or X resources. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-g " geometry" Set the initial window geometry. .RB ( \-geometry is equivalent.) .RB "[X resource: " xpdf.geometry ] .TP .BI \-title " title" Set the window title. By default, the title will be "xpdf: foo.pdf". .RB "[X resource: " xpdf.title ] .TP .B \-cmap Install a private colormap. This is ignored on TrueColor visuals. .RB "[X resource: " xpdf.installCmap ] .TP .BI \-rgb " number" Set the size of largest RGB cube xpdf will try to allocate. The default is 5 (for a 5x5x5 cube); set to a smaller number to conserve color table entries. This is ignored with private colormaps and on TrueColor visuals. .RB "[X resource: " xpdf.rgbCubeSize ] .TP .B \-rv Set reverse video mode. This reverses the colors of everything except images. It may not always produce great results for PDF files which do weird things with color. This also causes the paper color to default to black. .RB "[X resource: " xpdf.reverseVideo ] .TP .BI \-papercolor " color" Set the "paper color", i.e., the background of the page display. This will not work too well with PDF files that do things like filling in white behind the text. .RB "[X resource: " xpdf.paperColor ] .TP .BI \-mattecolor " color" Set the matte color, i.e., the color used for background outside the actual page area. (There is a separate setting, xpdf.fullScreenMatteColor, for full-screen mode.) .RB "[X resource: " xpdf.matteColor ] .TP .BI \-z " zoom" Set the initial zoom factor. A number specifies a zoom percentage, where 100 means 72 dpi. You may also specify \'page', to fit the page to the window size, or \'width', to fit the page width to the window width. .RB "[config file: " initialZoom "; or X resource: " xpdf.initialZoom ] .TP .B \-cont Start in continuous view mode, i.e., with one vertical scroll bar for the whole document. .RB "[config file: " continuousView ] .TP .BI \-t1lib " yes | no" Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". .RB "[config file: " enableT1lib ] .TP .BI \-freetype " yes | no" Enable or disable FreeType (a TrueType / Type 1 font rasterizer). This defaults to "yes". .RB "[config file: " enableFreeType ] .TP .BI \-aa " yes | no" Enable or disable font anti-aliasing. This defaults to "yes". .RB "[config file: " antialias ] .TP .BI \-aaVector " yes | no" Enable or disable vector anti-aliasing. This defaults to "yes". .RB "[config file: " vectorAntialias ] .TP .BI \-ps " PS-file" Set the default file name for PostScript output (i.e., the name which will appear in the print dialog). This can also be of the form \'|command' to pipe the PostScript through a command. .RB "[config file: " psFile ] .TP .BI \-paper " size" Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. .RB "[config file: " psPaperSize ] .TP .BI \-paperw " size" Set the paper width, in points. .RB "[config file: " psPaperSize ] .TP .BI \-paperh " size" Set the paper height, in points. .RB "[config file: " psPaperSize ] .TP .B \-level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. .RB "[config file: " psLevel ] .TP .BI \-enc " encoding-name" Sets the encoding to use for text output. The .I encoding\-name must be defined with the unicodeMap command (see .BR xpdfrc (5)). This defaults to "Latin1" (which is a built-in encoding). .RB "[config file: " textEncoding ] .TP .BI \-eol " unix | dos | mac" Sets the end-of-line convention to use for text output. .RB "[config file: " textEOL ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .B \-fullscreen Open xpdf in full-screen mode, useful for presentations. .TP .BI \-remote " name" Start/contact xpdf remote server with specified name (see the .B "REMOTE SERVER MODE" section below). .TP .BI \-exec " command" Execute a command (see the .B COMMANDS section below) in an xpdf remote server window (with \-remote only). .TP .B \-reload Reload xpdf remote server window (with \-remote only). .TP .B \-raise Raise xpdf remote server window (with \-remote only). .TP .B \-quit Kill xpdf remote server (with \-remote only). .TP .B \-cmd Print commands as they're executed (useful for debugging). .RB "[config file: " printCommands ] .TP .B \-q Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .PP Several other standard X options and resources will work as expected: .TP .BI \-display " display" .RB "[X resource: " xpdf.display ] .TP .BI \-fg " color" .RB ( \-foreground is equivalent.) .RB "[X resource: " xpdf*Foreground ] .TP .BI \-bg " color" .RB ( \-background is equivalent.) .RB "[X resource: " xpdf*Background ] .TP .BI \-font " font" .RB ( \-fn is equivalent.) .RB "[X resource: " xpdf*fontList ] .PP The color and font options only affect the user interface elements, not the PDF display (the \'paper'). .PP The following X resources do not have command line option equivalents: .TP .B xpdf.toolTipEnable Enables (if set to true) or disables (if set to false) the tool-tips on the toolbar buttons. .TP .B xpdf.fullScreenMatteColor Sets the matte color to be used in full-screen mode. The default setting is "black". .SH CONTROLS .SS On-screen controls, at the bottom of the xpdf window .TP .B "left/right arrow buttons" Move to the previous/next page. .TP .B "double left/right arrow buttons" Move backward or forward by ten pages. .TP .B "dashed left/right arrow buttons" Move backward or forward along the history path. .TP .B "\'Page' entry box" Move to a specific page number. Click in the box to activate it, type the page number, then hit return. .TP .B "zoom popup menu" Change the zoom factor (see the description of the \-z option above). .TP .B "binoculars button" Find a text string. .TP .B "print button" Bring up a dialog for generating a PostScript file. The dialog has options to set the pages to be printed and the PostScript file name. The file name can be \'-' for stdout or \'|command' to pipe the PostScript through a command, e.g., \'|lpr'. .TP .B "\'?' button" Bring up the \'about xpdf' window. .TP .B "link info" The space between the \'?' and \'Quit' buttons is used to show the URL or external file name when the mouse is over a link. .TP .B "\'Quit' button" Quit xpdf. .PP .SS Menu Pressing the right mouse button will post a popup menu with the following commands: .TP .B "Open..." Open a new PDF file via a file requester. .TP .B "Open in new window..." Create a new window and open a new PDF file via a file requester. .TP .B "Reload" Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. .TP .B "Save as..." Save the current file via a file requester. .TP .B "Continuous view" Toggles between single page and continuous view modes. .TP .B "Rotate counterclockwise" Rotate the page 90 degrees counterclockwise. .TP .B "Rotate clockwise" Rotate the page 90 degrees clockwise. The two rotate commands are intended primarily for PDF files where the rotation isn't correctly specified in the file. .TP .B "Zoom to selection" Zoom in to the currently selected rectangle. .TP .B "Close" Close the current window. If this is the only open window, the document is closed, but the window is left open (i.e., this menu command won't quit xpdf). .TP .B "Quit" Quit xpdf. .PP .SS Outline If the PDF contains an outline (a.k.a., bookmarks), there will be an outline pane on the left side of the window. The width of the outline pane is adjustable with a vertical split bar via the knob near its bottom end. .PP .SS Text selection Dragging the mouse with the left button held down will highlight an arbitrary rectangle. Any text inside this rectangle will be copied to the X selection buffer. .PP .SS Links Clicking on a hyperlink will jump to the link's destination. A link to another PDF document will make xpdf load that document. A \'launch' link to an executable program will display a dialog, and if you click \'ok', execute the program. URL links call an external command (see the .B WEB BROWSERS section below). .PP .SS Panning Dragging the mouse with the middle button held down pans the window. .PP .SS Key bindings .TP .B o Open a new PDF file via a file requester. .TP .B r Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. .TP .B control-L Redraw the current page. .TP .B control-W Close the current window. .TP .B f or control-F Find a text string. .TP .B control-G Find next occurrence. .TP .B control-P Print. .TP .B n Move to the next page. Scrolls to the top of the page, unless scroll lock is turned on. .TP .B p Move to the previous page. Scrolls to the top of the page, unless scroll lock is turned on. .TP .BR " or " " or " Scroll down on the current page; if already at bottom, move to next page. .TP .BR " or " " or " " or " Scroll up on the current page; if already at top, move to previous page. .TP .B v Move forward along the history path. .TP .B b Move backward along the history path. .TP .B Scroll to top of current page. .TP .B Scroll to bottom of current page. .TP .B control- Scroll to first page of document. .TP .B control- Scroll to last page of document. .TP .B arrows Scroll the current page. .TP .B g Activate the page number text field ("goto page"). .TP .B 0 Set the zoom factor to 125%. .TP .B + Zoom in (increment the zoom factor by 1). .TP .B - Zoom out (decrement the zoom factor by 1). .TP .B z Set the zoom factor to 'page' (fit page to window). .TP .B w Set the zoom factor to 'width' (fit page width to window). .TP .B alt-F Toggle full-screen mode. .TP .B q Quit xpdf. .SH "WEB BROWSERS" If you want to run xpdf automatically from netscape or mosaic (and probably other browsers) when you click on a link to a PDF file, you need to edit (or create) the files .I .mime.types and .I .mailcap in your home directory. In .I .mime.types add the line: .PP .RS application/pdf pdf .RE .PP In .I .mailcap add the lines: .PP .RS # Use xpdf to view PDF files. .RE .RS application/pdf; xpdf \-q %s .RE .PP Make sure that xpdf is on your executable search path. .PP When you click on a URL link in a PDF file, xpdf will execute the command specified by the urlCommand config file option, replacing an occurrence of \'%s' with the URL. For example, to call netscape with the URL, add this line to your config file: .PP .RS urlCommand "netscape \-remote 'openURL(%s)'" .RE .SH COMMANDS Xpdf's key and mouse bindings are user-configurable, using the bind and unbind options in the config file (see .BR xpdfrc (5)). The bind command allows you to bind a key or mouse button to a sequence of one or more commands. .SS Available Commands The following commands are supported: .TP .BI gotoPage( page ) Go to the specified page. .TP .BI gotoPageNoScroll( page ) Go to the specified page, with the current relative scroll position. .TP .BI gotoDest( dest ) Go to a named destination. .TP .B gotoLastPage Go to the last page in the PDF file. .TP .B gotoLastPageNoScroll Go to the last page in the PDF file, with the current relative scroll position. .TP .B nextPage Go to the next page. .TP .B nextPageNoScroll Go to the next page, with the current relative scroll position. .TP .B prevPage Go to the previous page. .TP .B prevPageNoScroll Go to the previous page, with the current relative scroll position. .TP .B pageUp Scroll up by one screenful. .TP .B pageDown Scroll down by one screenful. .TP .BI scrollLeft( n ) Scroll left by .I n pixels. .TP .BI scrollRight( n ) Scroll right by .I n pixels. .TP .BI scrollUp( n ) Scroll up by .I n pixels. .TP .BI scrollDown( n ) Scroll down by .I n pixels. .TP .BI scrollUpPrevPage( n ) Scroll up by .I n pixels, moving to the previous page if appropriate. .TP .BI scrollDownPrevPage( n ) Scroll down by .I n pixels, moving to the next page if appropriate. .TP .B scrollToTopEdge Scroll to the top edge of the current page, with no horizontal movement. .TP .B scrollToBottomEdge Scroll to the bottom edge of the current page, with no horizontal movement. .TP .B scrollToLeftEdge Scroll to the left edge of the current page, with no vertical movement. .TP .B scrollToRightEdge Scroll to the right edge of the current page, with no vertical movement. .TP .B scrollToTopLeft Scroll to the top-left corner of the current page. .TP .B scrollToBottomRight Scroll to the bottom-right corner of the current page. .TP .B goForward Move forward along the history path. .TP .B goBackward Move backward along the history path. .TP .BI zoomPercent( z ) Set the zoom factor to .IR z %. .TP .B zoomFitPage Set the zoom factor to fit-page. .TP .B zoomFitWidth Set the zoom factor to fit-width. .TP .B zoomIn Zoom in - go to the next higher zoom factor. .TP .B zoomOut Zoom out - go the next lower zoom factor. .TP .B rotateCW Rotate the page 90 degrees clockwise. .TP .B rotateCCW Rotate the page 90 degrees counterclockwise. .TP .BI setSelection( pg , ulx , uly , lrx , lry ) Set the selection to the specified coordinates on the specified page. .TP .B continuousMode Go to continuous view mode. .TP .B singlePageMode Go to single-page view mode. .TP .B toggleContinuousMode Toggle between continuous and single page view modes. .TP .B fullScreenMode Go to full-screen mode. .TP .B windowMode Go to window (non-full-screen) mode. .TP .B toggleFullScreenMode Toggle between full-screen and window modes. .TP .B open Open a PDF file in this window, using the open dialog. .TP .B openInNewWin Open a PDF file in a new window, using the open dialog. .TP .BI openFile( file ) Open a specified PDF file in this window. .TP .BI openFileInNewWin( file ) Open a specified PDF file in a new window. .TP .BI openFileAtDest( file , dest ) Open a specified PDF file in this window and go to a named destination. .TP .BI openFileAtDestInNewWin( file , dest ) Open a specified PDF file in a new window and go to a named destination. .TP .B reload Reload the current PDF file. .TP .B redraw Redraw the window. .TP .B raise Raise the window to the front. .TP .B closeWindow Close the window. .TP .BI run( external-command-string ) Run an external command. The following escapes are allowed in the command string: .nf %f => PDF file name (or an empty string if no file is open) %b => PDF file base name, i.e., file name minus the extension (or an empty string if no file is open) %u => link URL (or an empty string if not over a URL link) %p => current page number (or an empty string if no file is open) %x => selection upper-left x coordinate (or 0 if there is no selection) %y => selection upper-left y coordinate (or 0 if there is no selection) %X => selection lower-right x coordinate (or 0 if there is no selection) %Y => selection lower-right y coordinate (or 0 if there is no selection) %i => page containing the mouse pointer %j => x coordinate of the mouse pointer %k => y coordinate of the mouse pointer %% => % .fi .TP .B openOutline Open the outline pane. .TP .B closeOutline Close the outline pane. .TP .B toggleOutline Toggle the outline pane between open and closed. .TP .BI scrollOutlineDown( n ) Scroll the outline down by .I n increments. .TP .BI scrollOutlineUp( n ) Scroll the outline up by .I n increments. .TP .B focusToDocWin Set the keyboard focus to the main document window. .TP .B focusToPageNum Set the keyboard focus to the page number text box. .TP .B find Open the 'find' dialog. .TP .B findNext Finds the next occurrence of the search string (no dialog). .TP .B print Open the 'print' dialog. .TP .B about Open the 'about' dialog. .TP .B quit Quit from xpdf. .PP The following commands depend on the current mouse position: .TP .B startSelection Start a selection, which will be extended as the mouse moves. .TP .B endSelection End a selection. .TP .B startPan Start a pan, which will scroll the document as the mouse moves .TP .B endPan End a pan. .TP .B postPopupMenu Display the popup menu. .TP .B followLink Follow a hyperlink (does nothing if the mouse is not over a link). .TP .B followLinkInNewWin Follow a hyperlink, opening PDF files in a new window (does nothing if the mouse is not over a link). For links to non-PDF files, this command is identical to followLink. .TP .B followLinkNoSel Same as followLink, but does nothing if there is a non-empty selection. (This is useful as a mouse button binding.) .TP .B followLinkInNewWinNoSel Same as followLinkInNewWin, but does nothing if there is a non-empty selection. (This is useful as a mouse button binding.) .SS Default Bindings The default mouse bindings are as follows: .nf bind mousePress1 any startSelection bind mouseRelease1 any endSelection followLinkNoSel bind mousePress2 any startPan bind mouseRelease2 any endPan bind mousePress3 any postPopupMenu bind mousePress4 any scrollUpPrevPage(16) bind mousePress5 any scrollDownNextPage(16) bind mousePress6 any scrollLeft(16) bind mousePress7 any scrollRight(16) .fi The default key bindings are as follows: .nf bind ctrl-home any gotoPage(1) bind home any scrollToTopLeft bind ctrl-end any gotoLastPage bind end any scrollToBottomRight bind pgup any pageUp bind backspace any pageUp bind delete any pageUp bind pgdn any pageDown bind space any pageDown bind left any scrollLeft(16) bind right any scrollRight(16) bind up any scrollUp(16) bind down any scrollDown(16) bind o any open bind O any open bind r any reload bind R any reload bind f any find bind F any find bind ctrl-f any find bind ctrl-g any findNext bind ctrl-p any print bind n scrLockOff nextPage bind N scrLockOff nextPage bind n scrLockOn nextPageNoScroll bind N scrLockOn nextPageNoScroll bind p scrLockOff prevPage bind P scrLockOff prevPage bind p scrLockOn prevPageNoScroll bind P scrLockOn prevPageNoScroll bind v any goForward bind b any goBackward bind g any focusToPageNum bind 0 any zoomPercent(125) bind + any zoomIn bind - any zoomOut bind z any zoomFitPage bind w any zoomFitWidth bind alt-f any toggleFullScreenMode bind ctrl-l any redraw bind ctrl-w any closeWindow bind ? any about bind q any quit bind Q any quit .fi Previous versions of xpdf included a "viKeys" X resource. It is no longer available, but the following bindings are equivalent: .nf bind h any scrollLeft(16) bind l any scrollRight(16) bind k any scrollUp(16) bind j any scrollDown(16) .fi .SH "REMOTE SERVER MODE" Xpdf can be started in remote server mode by specifying a server name (in addition to the file name and page number). For example: .PP .RS xpdf \-remote myServer file.pdf .RE .PP If there is currently no xpdf running in server mode with the name \'myServer', a new xpdf window will be opened. If another command: .PP .RS xpdf \-remote myServer another.pdf 9 .RE .PP is issued, a new copy of xpdf will not be started. Instead, the first xpdf (the server) will load .I another.pdf and display page nine. If the file name is the same: .PP .RS xpdf \-remote myServer another.pdf 4 .RE .PP the xpdf server will simply display the specified page. .PP The \-raise option tells the server to raise its window; it can be specified with or without a file name and page number. .PP The \-quit option tells the server to close its window and exit. .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdfdetach.10000644000076400007640000000537311622305345014474 0ustar dereknderekn.\" Copyright 2011 Glyph & Cog, LLC .TH pdfdetach 1 "15 August 2011" .SH NAME pdfdetach \- Portable Document Format (PDF) document embedded file extractor (version 3.03) .SH SYNOPSIS .B pdfdetach [options] .RI [ PDF-file ] .SH DESCRIPTION .B Pdfdetach lists or extracts embedded files (attachments) from a Portable Document Format (PDF) file. .SH CONFIGURATION FILE Pdfdetach reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Some of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .B \-list List all of the embedded files in the PDF file. File names are converted to the text encoding specified by the "\-enc" switch. .TP .BI \-save " number" Save the specified embedded file. By default, this uses the file name associated with the embedded file (as printed by the "\-list" switch); the file name can be changed with the "\-o" switch. .TP .BI \-saveall Save all of the embedded files. This uses the file names associated with the embedded files (as printed by the "\-list" switch). By default, the files are saved in the current directory; this can be changed with the "\-o" switch. .TP .BI \-o " path" Set the file name used when saving an embedded file with the "\-save" switch, or the directory used by "\-saveall". .TP .BI \-enc " encoding-name" Sets the encoding to use for text output (embedded file names). The .I encoding\-name must be defined with the unicodeMap command (see .BR xpdfrc (5)). This defaults to "Latin1" (which is a built-in encoding). .RB "[config file: " textEncoding ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdfdetach.cat0000644000076400007640000000633311622305345015100 0ustar derekndereknpdfdetach(1) pdfdetach(1) NAME pdfdetach - Portable Document Format (PDF) document embedded file extractor (version 3.03) SYNOPSIS pdfdetach [options] [PDF-file] DESCRIPTION Pdfdetach lists or extracts embedded files (attachments) from a Porta- ble Document Format (PDF) file. CONFIGURATION FILE Pdfdetach reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the xpdfrc(5) man page for details. OPTIONS Some of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -list List all of the embedded files in the PDF file. File names are converted to the text encoding specified by the "-enc" switch. -save number Save the specified embedded file. By default, this uses the file name associated with the embedded file (as printed by the "-list" switch); the file name can be changed with the "-o" switch. -saveall Save all of the embedded files. This uses the file names asso- ciated with the embedded files (as printed by the "-list" switch). By default, the files are saved in the current direc- tory; this can be changed with the "-o" switch. -o path Set the file name used when saving an embedded file with the "-save" switch, or the directory used by "-saveall". -enc encoding-name Sets the encoding to use for text output (embedded file names). The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [config file: textEncoding] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdfdetach(1) xpdf-3.03/doc/pdftops.cat0000644000076400007640000002047311622305345014636 0ustar derekndereknpdftops(1) pdftops(1) NAME pdftops - Portable Document Format (PDF) to PostScript converter (ver- sion 3.03) SYNOPSIS pdftops [options] [PDF-file [PS-file]] DESCRIPTION Pdftops converts Portable Document Format (PDF) files to PostScript so they can be printed. Pdftops reads the PDF file, PDF-file, and writes a PostScript file, PS- file. If PS-file is not specified, pdftops converts file.pdf to file.ps (or file.eps with the -eps option). If PS-file is '-', the PostScript is sent to stdout. CONFIGURATION FILE Pdftops reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftops is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to print. -l number Specifies the last page to print. -level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. No more than one of the PostScript level options (-level1, -level1sep, -level2, -level2sep, -level3, -level3Sep) may be given. [config file: psLevel] -level1sep Generate Level 1 separable PostScript. All colors are converted to CMYK. Images are written with separate stream data for the four components. [config file: psLevel] -level2 Generate Level 2 PostScript. Level 2 supports color images and image compression. This is the default setting. [config file: psLevel] -level2sep Generate Level 2 separable PostScript. All colors are converted to CMYK. The PostScript separation convention operators are used to handle custom (spot) colors. [config file: psLevel] -level3 Generate Level 3 PostScript. This enables all Level 2 features plus CID font embedding and masked image generation. [config file: psLevel] -level3Sep Generate Level 3 separable PostScript. The separation handling is the same as for -level2Sep. [config file: psLevel] -eps Generate an Encapsulated PostScript (EPS) file. An EPS file contains a single image, so if you use this option with a multi- page PDF file, you must use -f and -l to specify a single page. No more than one of the mode options (-eps, -form) may be given. -form Generate a PostScript form which can be imported by software that understands forms. A form contains a single page, so if you use this option with a multi-page PDF file, you must use -f and -l to specify a single page. The -level1 option cannot be used with -form. -opi Generate OPI comments for all images and forms which have OPI information. (This option is only available if pdftops was com- piled with OPI support.) [config file: psOPI] -noembt1 By default, any Type 1 fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make Post- Script files larger, but may be necessary for readable output. [config file: psEmbedType1Fonts] -noembtt By default, any TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make PostScript files larger, but may be necessary for readable out- put. Also, some PostScript interpreters do not have TrueType rasterizers. [config file: psEmbedTrueTypeFonts] -noembcidps By default, any CID PostScript fonts which are embedded in the PDF file are copied into the PostScript file. This option dis- ables that embedding. No attempt is made to substitute for non- embedded CID PostScript fonts. [config file: psEmbedCID- PostScriptFonts] -noembcidtt By default, any CID TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option disables that embedding. No attempt is made to substitute for non-embed- ded CID TrueType fonts. [config file: psEmbedCIDTrueTypeFonts] -preload Convert PDF forms to PS procedures, and preload image data. This uses more memory in the PostScript interpreter, but gener- ates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. -paper size Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. [config file: psPaperSize] -paperw size Set the paper width, in points. [config file: psPaperSize] -paperh size Set the paper height, in points. [config file: psPaperSize] -nocrop By default, output is cropped to the CropBox specified in the PDF file. This option disables cropping. [config file: psCrop] -expand Expand PDF pages smaller than the paper to fill the paper. By default, these pages are not scaled. [config file: psExpandS- maller] -noshrink Don't scale PDF pages which are larger than the paper. By default, pages larger than the paper are shrunk to fit. [config file: psShrinkLarger] -nocenter By default, PDF pages smaller than the paper (after any scaling) are centered on the paper. This option causes them to be aligned to the lower-left corner of the paper instead. [config file: psCenter] -pagecrop Treat the CropBox as the PDF page size. By default, the Media- Box is used as the page size. -duplex Set the Duplex pagedevice entry in the PostScript file. This tells duplex-capable printers to enable duplexing. [config file: psDuplex] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdftops software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdftops(1) xpdf-3.03/doc/pdffonts.hlp0000644000076400007640000000726311622305345015020 0ustar dereknderekn! Generated automatically by mantohlp 1 pdffonts pdffonts - Portable Document Format (PDF) font analyzer (version pdffonts [options] [PDF-file] Pdffonts lists the fonts used in a Portable Document Format (PDF) file along with various information for each font. The following information is listed for each font: name the font name, exactly as given in the PDF file (potentially including a subset prefix) type the font type -- see below for details emb "yes" if the font is embedded in the PDF file sub "yes" if the font is a subset uni "yes" if there is an explicit "ToUnicode" map in the PDF file (the absence of a ToUnicode map doesn't necessarily mean that the text can't be converted to Unicode) object ID the font dictionary object ID (number and generation) PDF files can contain the following types of fonts: Type 1 Type 1C -- aka Compact Font Format (CFF) Type 1C (OT) -- OpenType with 8-bit CFF data Type 3 TrueType TrueType (OT) -- OpenType with 8-bit TrueType data CID Type 0 -- 16-bit font with no specified type CID Type 0C -- 16-bit PostScript CFF font CID Type 0C (OT) -- OpenType with CID CFF data CID TrueType -- 16-bit TrueType font CID TrueType (OT) -- OpenType with CID TrueType data () 2 ONFIGURATION_FIL Pdffonts reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdffonts is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to analyze. -l number Specifies the last page to analyze. -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdffonts software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/xpdf.hlp0000644000076400007640000006571411622305345014143 0ustar dereknderekn! Generated automatically by mantohlp 1 xpdf xpdf - Portable Document Format (PDF) file viewer for X (version 3.03) xpdf [options] [PDF-file [page | +dest]] Xpdf is a viewer for Portable Document Format (PDF) files. (These are also sometimes also called 'Acrobat' files, from the name of Adobe's PDF software.) Xpdf runs under the X Window System on UNIX, VMS, and OS/2. To run xpdf, simply type: xpdf file.pdf where file.pdf is your PDF file. The file name can be followed by a number specifying the page which should be displayed first, e.g.: xpdf file.pdf 18 You can also give a named destination, prefixed with '+' in place of the page number. (This is only useful with PDF files that provide named destination targets.) You can also start xpdf without opening any files: xpdf () 2 ONFIGURATION_FIL Xpdf reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when xpdf is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands or X resources. These are listed in square brackets with the description of the corresponding command line option. -g geometry Set the initial window geometry. (-geometry is equivalent.) [X resource: xpdf.geometry] -title title Set the window title. By default, the title will be "xpdf: foo.pdf". [X resource: xpdf.title] -cmap Install a private colormap. This is ignored on TrueColor visu- als. [X resource: xpdf.installCmap] -rgb number Set the size of largest RGB cube xpdf will try to allocate. The default is 5 (for a 5x5x5 cube); set to a smaller number to con- serve color table entries. This is ignored with private col- ormaps and on TrueColor visuals. [X resource: xpdf.rgbCubeSize] -rv Set reverse video mode. This reverses the colors of everything except images. It may not always produce great results for PDF files which do weird things with color. This also causes the paper color to default to black. [X resource: xpdf.reverseV- ideo] -papercolor color Set the "paper color", i.e., the background of the page display. This will not work too well with PDF files that do things like filling in white behind the text. [X resource: xpdf.paperColor] -mattecolor color Set the matte color, i.e., the color used for background outside the actual page area. (There is a separate setting, xpdf.fullScreenMatteColor, for full-screen mode.) [X resource: xpdf.matteColor] -z zoom Set the initial zoom factor. A number specifies a zoom percent- age, where 100 means 72 dpi. You may also specify 'page', to fit the page to the window size, or 'width', to fit the page width to the window width. [config file: initialZoom; or X resource: xpdf.initialZoom] -cont Start in continuous view mode, i.e., with one vertical scroll bar for the whole document. [config file: continuousView] -t1lib yes | no Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". [config file: enableT1lib] -freetype yes | no Enable or disable FreeType (a TrueType / Type 1 font raster- izer). This defaults to "yes". [config file: enableFreeType] -aa yes | no Enable or disable font anti-aliasing. This defaults to "yes". [config file: antialias] -aaVector yes | no Enable or disable vector anti-aliasing. This defaults to "yes". [config file: vectorAntialias] -ps PS-file Set the default file name for PostScript output (i.e., the name which will appear in the print dialog). This can also be of the form '|command' to pipe the PostScript through a command. [con- fig file: psFile] -paper size Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. [config file: psPaperSize] -paperw size Set the paper width, in points. [config file: psPaperSize] -paperh size Set the paper height, in points. [config file: psPaperSize] -level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. [config file: psLevel] -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [con- fig file: textEncoding] -eol unix | dos | mac Sets the end-of-line convention to use for text output. [config file: textEOL] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -fullscreen Open xpdf in full-screen mode, useful for presentations. -remote name Start/contact xpdf remote server with specified name (see the REMOTE SERVER MODE section below). -exec command Execute a command (see the COMMANDS section below) in an xpdf remote server window (with -remote only). -reload Reload xpdf remote server window (with -remote only). -raise Raise xpdf remote server window (with -remote only). -quit Kill xpdf remote server (with -remote only). -cmd Print commands as they're executed (useful for debugging). [config file: printCommands] -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) Several other standard X options and resources will work as expected: -display display [X resource: xpdf.display] -fg color (-foreground is equivalent.) [X resource: xpdf*Foreground] -bg color (-background is equivalent.) [X resource: xpdf*Background] -font font (-fn is equivalent.) [X resource: xpdf*fontList] The color and font options only affect the user interface elements, not the PDF display (the 'paper'). The following X resources do not have command line option equivalents: xpdf.toolTipEnable Enables (if set to true) or disables (if set to false) the tool- tips on the toolbar buttons. xpdf.fullScreenMatteColor Sets the matte color to be used in full-screen mode. The default setting is "black". () 2 CONTROLS On-screen controls, at the bottom of the xpdf window left/right arrow buttons Move to the previous/next page. double left/right arrow buttons Move backward or forward by ten pages. dashed left/right arrow buttons Move backward or forward along the history path. 'Page' entry box Move to a specific page number. Click in the box to activate it, type the page number, then hit return. zoom popup menu Change the zoom factor (see the description of the -z option above). binoculars button Find a text string. print button Bring up a dialog for generating a PostScript file. The dialog has options to set the pages to be printed and the PostScript file name. The file name can be '-' for stdout or '|command' to pipe the PostScript through a command, e.g., '|lpr'. '?' button Bring up the 'about xpdf' window. link info The space between the '?' and 'Quit' buttons is used to show the URL or external file name when the mouse is over a link. 'Quit' button Quit xpdf. Menu Pressing the right mouse button will post a popup menu with the follow- ing commands: Open... Open a new PDF file via a file requester. Open in new window... Create a new window and open a new PDF file via a file requester. Reload Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. Save as... Save the current file via a file requester. Continuous view Toggles between single page and continuous view modes. Rotate counterclockwise Rotate the page 90 degrees counterclockwise. Rotate clockwise Rotate the page 90 degrees clockwise. The two rotate commands are intended primarily for PDF files where the rotation isn't correctly specified in the file. Zoom to selection Zoom in to the currently selected rectangle. Close Close the current window. If this is the only open window, the document is closed, but the window is left open (i.e., this menu command won't quit xpdf). Quit Quit xpdf. Outline If the PDF contains an outline (a.k.a., bookmarks), there will be an outline pane on the left side of the window. The width of the outline pane is adjustable with a vertical split bar via the knob near its bot- tom end. Text selection Dragging the mouse with the left button held down will highlight an arbitrary rectangle. Any text inside this rectangle will be copied to the X selection buffer. Links Clicking on a hyperlink will jump to the link's destination. A link to another PDF document will make xpdf load that document. A 'launch' link to an executable program will display a dialog, and if you click 'ok', execute the program. URL links call an external command (see the WEB BROWSERS section below). Panning Dragging the mouse with the middle button held down pans the window. Key bindings o Open a new PDF file via a file requester. r Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. control-L Redraw the current page. control-W Close the current window. f or control-F Find a text string. control-G Find next occurrence. control-P Print. n Move to the next page. Scrolls to the top of the page, unless scroll lock is turned on. p Move to the previous page. Scrolls to the top of the page, unless scroll lock is turned on. or or Scroll down on the current page; if already at bottom, move to next page. or or or Scroll up on the current page; if already at top, move to previ- ous page. v Move forward along the history path. b Move backward along the history path. Scroll to top of current page. Scroll to bottom of current page. control- Scroll to first page of document. control- Scroll to last page of document. arrows Scroll the current page. g Activate the page number text field ("goto page"). 0 Set the zoom factor to 125%. + Zoom in (increment the zoom factor by 1). - Zoom out (decrement the zoom factor by 1). z Set the zoom factor to 'page' (fit page to window). w Set the zoom factor to 'width' (fit page width to window). alt-F Toggle full-screen mode. q Quit xpdf. () 2 WEB_BROWSERS If you want to run xpdf automatically from netscape or mosaic (and probably other browsers) when you click on a link to a PDF file, you need to edit (or create) the files .mime.types and .mailcap in your home directory. In .mime.types add the line: application/pdf pdf In .mailcap add the lines: # Use xpdf to view PDF files. application/pdf; xpdf -q %s Make sure that xpdf is on your executable search path. When you click on a URL link in a PDF file, xpdf will execute the com- mand specified by the urlCommand config file option, replacing an occurrence of '%s' with the URL. For example, to call netscape with the URL, add this line to your config file: urlCommand "netscape -remote 'openURL(%s)'" () 2 COMMANDS Xpdf's key and mouse bindings are user-configurable, using the bind and unbind options in the config file (see xpdfrc(5)). The bind command allows you to bind a key or mouse button to a sequence of one or more commands. Available Commands The following commands are supported: gotoPage(page) Go to the specified page. gotoPageNoScroll(page) Go to the specified page, with the current relative scroll posi- tion. gotoDest(dest) Go to a named destination. gotoLastPage Go to the last page in the PDF file. gotoLastPageNoScroll Go to the last page in the PDF file, with the current relative scroll position. nextPage Go to the next page. nextPageNoScroll Go to the next page, with the current relative scroll position. prevPage Go to the previous page. prevPageNoScroll Go to the previous page, with the current relative scroll posi- tion. pageUp Scroll up by one screenful. pageDown Scroll down by one screenful. scrollLeft(n) Scroll left by n pixels. scrollRight(n) Scroll right by n pixels. scrollUp(n) Scroll up by n pixels. scrollDown(n) Scroll down by n pixels. scrollUpPrevPage(n) Scroll up by n pixels, moving to the previous page if appropri- ate. scrollDownPrevPage(n) Scroll down by n pixels, moving to the next page if appropriate. scrollToTopEdge Scroll to the top edge of the current page, with no horizontal movement. scrollToBottomEdge Scroll to the bottom edge of the current page, with no horizon- tal movement. scrollToLeftEdge Scroll to the left edge of the current page, with no vertical movement. scrollToRightEdge Scroll to the right edge of the current page, with no vertical movement. scrollToTopLeft Scroll to the top-left corner of the current page. scrollToBottomRight Scroll to the bottom-right corner of the current page. goForward Move forward along the history path. goBackward Move backward along the history path. zoomPercent(z) Set the zoom factor to z%. zoomFitPage Set the zoom factor to fit-page. zoomFitWidth Set the zoom factor to fit-width. zoomIn Zoom in - go to the next higher zoom factor. zoomOut Zoom out - go the next lower zoom factor. rotateCW Rotate the page 90 degrees clockwise. rotateCCW Rotate the page 90 degrees counterclockwise. setSelection(pg,ulx,uly,lrx,lry) Set the selection to the specified coordinates on the specified page. continuousMode Go to continuous view mode. singlePageMode Go to single-page view mode. toggleContinuousMode Toggle between continuous and single page view modes. fullScreenMode Go to full-screen mode. windowMode Go to window (non-full-screen) mode. toggleFullScreenMode Toggle between full-screen and window modes. open Open a PDF file in this window, using the open dialog. openInNewWin Open a PDF file in a new window, using the open dialog. openFile(file) Open a specified PDF file in this window. openFileInNewWin(file) Open a specified PDF file in a new window. openFileAtDest(file,dest) Open a specified PDF file in this window and go to a named des- tination. openFileAtDestInNewWin(file,dest) Open a specified PDF file in a new window and go to a named des- tination. reload Reload the current PDF file. redraw Redraw the window. raise Raise the window to the front. closeWindow Close the window. run(external-command-string) Run an external command. The following escapes are allowed in the command string: %f => PDF file name (or an empty string if no file is open) %b => PDF file base name, i.e., file name minus the extension (or an empty string if no file is open) %u => link URL (or an empty string if not over a URL link) %p => current page number (or an empty string if no file is open) %x => selection upper-left x coordinate (or 0 if there is no selection) %y => selection upper-left y coordinate (or 0 if there is no selection) %X => selection lower-right x coordinate (or 0 if there is no selection) %Y => selection lower-right y coordinate (or 0 if there is no selection) %i => page containing the mouse pointer %j => x coordinate of the mouse pointer %k => y coordinate of the mouse pointer %% => % openOutline Open the outline pane. closeOutline Close the outline pane. toggleOutline Toggle the outline pane between open and closed. scrollOutlineDown(n) Scroll the outline down by n increments. scrollOutlineUp(n) Scroll the outline up by n increments. focusToDocWin Set the keyboard focus to the main document window. focusToPageNum Set the keyboard focus to the page number text box. find Open the 'find' dialog. findNext Finds the next occurrence of the search string (no dialog). print Open the 'print' dialog. about Open the 'about' dialog. quit Quit from xpdf. The following commands depend on the current mouse position: startSelection Start a selection, which will be extended as the mouse moves. endSelection End a selection. startPan Start a pan, which will scroll the document as the mouse moves endPan End a pan. postPopupMenu Display the popup menu. followLink Follow a hyperlink (does nothing if the mouse is not over a link). followLinkInNewWin Follow a hyperlink, opening PDF files in a new window (does nothing if the mouse is not over a link). For links to non-PDF files, this command is identical to followLink. followLinkNoSel Same as followLink, but does nothing if there is a non-empty selection. (This is useful as a mouse button binding.) followLinkInNewWinNoSel Same as followLinkInNewWin, but does nothing if there is a non- empty selection. (This is useful as a mouse button binding.) Default Bindings The default mouse bindings are as follows: bind mousePress1 any startSelection bind mouseRelease1 any endSelection followLinkNoSel bind mousePress2 any startPan bind mouseRelease2 any endPan bind mousePress3 any postPopupMenu bind mousePress4 any scrollUpPrevPage(16) bind mousePress5 any scrollDownNextPage(16) bind mousePress6 any scrollLeft(16) bind mousePress7 any scrollRight(16) The default key bindings are as follows: bind ctrl-home any gotoPage(1) bind home any scrollToTopLeft bind ctrl-end any gotoLastPage bind end any scrollToBottomRight bind pgup any pageUp bind backspace any pageUp bind delete any pageUp bind pgdn any pageDown bind space any pageDown bind left any scrollLeft(16) bind right any scrollRight(16) bind up any scrollUp(16) bind down any scrollDown(16) bind o any open bind O any open bind r any reload bind R any reload bind f any find bind F any find bind ctrl-f any find bind ctrl-g any findNext bind ctrl-p any print bind n scrLockOff nextPage bind N scrLockOff nextPage bind n scrLockOn nextPageNoScroll bind N scrLockOn nextPageNoScroll bind p scrLockOff prevPage bind P scrLockOff prevPage bind p scrLockOn prevPageNoScroll bind P scrLockOn prevPageNoScroll bind v any goForward bind b any goBackward bind g any focusToPageNum bind 0 any zoomPercent(125) bind + any zoomIn bind - any zoomOut bind z any zoomFitPage bind w any zoomFitWidth bind alt-f any toggleFullScreenMode bind ctrl-l any redraw bind ctrl-w any closeWindow bind ? any about bind q any quit bind Q any quit Previous versions of xpdf included a "viKeys" X resource. It is no longer available, but the following bindings are equivalent: bind h any scrollLeft(16) bind l any scrollRight(16) bind k any scrollUp(16) bind j any scrollDown(16) () 2 REMOTE_SERVER_MODE Xpdf can be started in remote server mode by specifying a server name (in addition to the file name and page number). For example: xpdf -remote myServer file.pdf If there is currently no xpdf running in server mode with the name 'myServer', a new xpdf window will be opened. If another command: xpdf -remote myServer another.pdf 9 is issued, a new copy of xpdf will not be started. Instead, the first xpdf (the server) will load another.pdf and display page nine. If the file name is the same: xpdf -remote myServer another.pdf 4 the xpdf server will simply display the specified page. The -raise option tells the server to raise its window; it can be spec- ified with or without a file name and page number. The -quit option tells the server to close its window and exit. () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/pdftops.10000644000076400007640000001577711622305345014242 0ustar dereknderekn.\" Copyright 1996-2011 Glyph & Cog, LLC .TH pdftops 1 "15 August 2011" .SH NAME pdftops \- Portable Document Format (PDF) to PostScript converter (version 3.03) .SH SYNOPSIS .B pdftops [options] .RI [ PDF-file .RI [ PS-file ]] .SH DESCRIPTION .B Pdftops converts Portable Document Format (PDF) files to PostScript so they can be printed. .PP Pdftops reads the PDF file, .IR PDF-file , and writes a PostScript file, .IR PS-file . If .I PS-file is not specified, pdftops converts .I file.pdf to .I file.ps (or .I file.eps with the \-eps option). If .I PS-file is \'-', the PostScript is sent to stdout. .SH CONFIGURATION FILE Pdftops reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftops is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to print. .TP .BI \-l " number" Specifies the last page to print. .TP .B \-level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. No more than one of the PostScript level options (\-level1, \-level1sep, \-level2, \-level2sep, \-level3, \-level3Sep) may be given. .RB "[config file: " psLevel ] .TP .B \-level1sep Generate Level 1 separable PostScript. All colors are converted to CMYK. Images are written with separate stream data for the four components. .RB "[config file: " psLevel ] .TP .B \-level2 Generate Level 2 PostScript. Level 2 supports color images and image compression. This is the default setting. .RB "[config file: " psLevel ] .TP .B \-level2sep Generate Level 2 separable PostScript. All colors are converted to CMYK. The PostScript separation convention operators are used to handle custom (spot) colors. .RB "[config file: " psLevel ] .TP .B \-level3 Generate Level 3 PostScript. This enables all Level 2 features plus CID font embedding and masked image generation. .RB "[config file: " psLevel ] .TP .B \-level3Sep Generate Level 3 separable PostScript. The separation handling is the same as for \-level2Sep. .RB "[config file: " psLevel ] .TP .B \-eps Generate an Encapsulated PostScript (EPS) file. An EPS file contains a single image, so if you use this option with a multi-page PDF file, you must use \-f and \-l to specify a single page. No more than one of the mode options (\-eps, \-form) may be given. .TP .B \-form Generate a PostScript form which can be imported by software that understands forms. A form contains a single page, so if you use this option with a multi-page PDF file, you must use \-f and \-l to specify a single page. The \-level1 option cannot be used with \-form. .TP .B \-opi Generate OPI comments for all images and forms which have OPI information. (This option is only available if pdftops was compiled with OPI support.) .RB "[config file: " psOPI ] .TP .B \-noembt1 By default, any Type 1 fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make PostScript files larger, but may be necessary for readable output. .RB "[config file: " psEmbedType1Fonts ] .TP .B \-noembtt By default, any TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make PostScript files larger, but may be necessary for readable output. Also, some PostScript interpreters do not have TrueType rasterizers. .RB "[config file: " psEmbedTrueTypeFonts ] .TP .B \-noembcidps By default, any CID PostScript fonts which are embedded in the PDF file are copied into the PostScript file. This option disables that embedding. No attempt is made to substitute for non-embedded CID PostScript fonts. .RB "[config file: " psEmbedCIDPostScriptFonts ] .TP .B \-noembcidtt By default, any CID TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option disables that embedding. No attempt is made to substitute for non-embedded CID TrueType fonts. .RB "[config file: " psEmbedCIDTrueTypeFonts ] .TP .B \-preload Convert PDF forms to PS procedures, and preload image data. This uses more memory in the PostScript interpreter, but generates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. .TP .BI \-paper " size" Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. .RB "[config file: " psPaperSize ] .TP .BI \-paperw " size" Set the paper width, in points. .RB "[config file: " psPaperSize ] .TP .BI \-paperh " size" Set the paper height, in points. .RB "[config file: " psPaperSize ] .TP .B \-nocrop By default, output is cropped to the CropBox specified in the PDF file. This option disables cropping. .RB "[config file: " psCrop ] .TP .B \-expand Expand PDF pages smaller than the paper to fill the paper. By default, these pages are not scaled. .RB "[config file: " psExpandSmaller ] .TP .B \-noshrink Don't scale PDF pages which are larger than the paper. By default, pages larger than the paper are shrunk to fit. .RB "[config file: " psShrinkLarger ] .TP .B \-nocenter By default, PDF pages smaller than the paper (after any scaling) are centered on the paper. This option causes them to be aligned to the lower-left corner of the paper instead. .RB "[config file: " psCenter ] .TP .B \-pagecrop Treat the CropBox as the PDF page size. By default, the MediaBox is used as the page size. .TP .B \-duplex Set the Duplex pagedevice entry in the PostScript file. This tells duplex-capable printers to enable duplexing. .RB "[config file: " psDuplex ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .B \-q Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdftops software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/xpdfrc.hlp0000644000076400007640000007146211622305345014465 0ustar dereknderekn! Generated automatically by mantohlp 1 xpdfrc 2 NCLUDE_FILE xpdfrc - configuration file for Xpdf tools (version 3.03) include config-file Includes the specified config file. The effect of this is equivalent to inserting the contents of config-file directly into the parent config file in place of the include command. Config files can be nested arbitrarily deeply. () 2 HARACTER_MAPPIN nameToUnicode map-file Specifies a file with the mapping from character names to Uni- code. This is used to handle PDF fonts that have valid encod- ings but no ToUnicode entry. Each line of a nameToUnicode file looks like this: hex-string name The hex-string is the Unicode (UCS-2) character index, and name is the corresponding character name. Multiple nameToUnicode files can be used; if a character name is given more than once, the code in the last specified file is used. There is a built- in default nameToUnicode table with all of Adobe's standard character names. cidToUnicode registry-ordering map-file Specifies the file with the mapping from character collection to Unicode. Each line of a cidToUnicode file represents one char- acter: hex-string The hex-string is the Unicode (UCS-2) index for that character. The first line maps CID 0, the second line CID 1, etc. File size is determined by size of the character collection. Only one file is allowed per character collection; the last specified file is used. There are no built-in cidToUnicode mappings. unicodeToUnicode font-name-substring map-file This is used to work around PDF fonts which have incorrect Uni- code information. It specifies a file which maps from the given (incorrect) Unicode indexes to the correct ones. The mapping will be used for any font whose name contains font-name-sub- string. Each line of a unicodeToUnicode file represents one Unicode character: in-hex out-hex1 out-hex2 ... The in-hex field is an input (incorrect) Unicode index, and the rest of the fields are one or more output (correct) Unicode indexes. Each occurrence of in-hex will be converted to the specified output sequence. unicodeMap encoding-name map-file Specifies the file with mapping from Unicode to encoding-name. These encodings are used for text output (see below). Each line of a unicodeMap file represents a range of one or more Unicode characters which maps linearly to a range in the output encod- ing: in-start-hex in-end-hex out-start-hex Entries for single characters can be abbreviated to: in-hex out-hex The in-start-hex and in-end-hex fields (or the single in-hex field) specify the Unicode range. The out-start-hex field (or the out-hex field) specifies the start of the output encoding range. The length of the out-start-hex (or out-hex) string determines the length of the output characters (e.g., UTF-8 uses different numbers of bytes to represent characters in different ranges). Entries must be given in increasing Unicode order. Only one file is allowed per encoding; the last specified file is used. The Latin1, ASCII7, Symbol, ZapfDingbats, UTF-8, and UCS-2 encodings are predefined. cMapDir registry-ordering dir Specifies a search directory, dir, for CMaps for the reg- istry-ordering character collection. There can be multiple directories for a particular collection. There are no default CMap directories. toUnicodeDir dir Specifies a search directory, dir, for ToUnicode CMaps. There can be multiple ToUnicode directories. There are no default ToUnicode directories. () 2 ENERAL_FONT_CONFIGURATIO fontFile PDF-font-name font-file Maps a PDF font, PDF-font-name, to a font for display or Post- Script output. The font file, font-file, can be any type allowed in a PDF file. This command can be used for 8-bit or 16-bit (CID) fonts. fontDir dir Specifies a search directory for font files. There can be mul- tiple fontDir commands; all of the specified directories will be searched in order. The font files can be Type 1 (.pfa or .pfb) or TrueType (.ttf or .ttc); other files in the directory will be ignored. The font file name (not including the extension) must exactly match the PDF font name. This search is performed if the font name doesn't match any of the fonts declared with the fontFile command. There are no default fontDir directories. fontFileCC registry-ordering font-file Maps the registry-ordering character collection to a font for display or PostScript output. This mapping is used if the font name doesn't match any of the fonts declared with the fontFile, fontDir, psResidentFont16, or psResidentFontCC commands. () 2 OSTSCRIPT_FONT_CONFIGURATIO psFontPassthrough yes | no If set to "yes", pass 8-bit font names through to the PostScript output without substitution. Fonts which are not embedded in the PDF file are expected to be available on the printer. This defaults to "no". psResidentFont PDF-font-name PS-font-name When the 8-bit font PDF-font-name is used (without embedding) in a PDF file, it will be translated to the PostScript font PS-font-name, which is assumed to be resident in the printer. Typically, PDF-font-name and PS-font-name are the same. By default, only the Base-14 fonts are assumed to be resident. psResidentFont16 PDF-font-name wMode PS-font-name encoding When the 16-bit (CID) font PDF-font-name with writing mode wMode is used (without embedding) in a PDF file, it will be translated to the PostScript font PS-font-name, which is assumbed to be resident in the printer. The writing mode must be either 'H' for horizontal or 'V' for vertical. The resident font is assumed to use the specified encoding (which must have been defined with the unicodeMap command). psResidentFontCC registry-ordering wMode PS-font-name encoding When a 16-bit (CID) font using the registry-ordering character collection and wMode writing mode is used (without embedding) in a PDF file, the PostScript font, PS-font-name, is substituted for it. The substituted font is assumbed to be resident in the printer. The writing mode must be either 'H' for horizontal or 'V' for vertical. The resident font is assumed to use the spec- ified encoding (which must have been defined with the unicodeMap command). psEmbedType1Fonts yes | no If set to "no", prevents embedding of Type 1 fonts in generated PostScript. This defaults to "yes". psEmbedTrueTypeFonts yes | no If set to "no", prevents embedding of TrueType fonts in gener- ated PostScript. This defaults to "yes". psEmbedCIDTrueTypeFonts yes | no If set to "no", prevents embedding of CID TrueType fonts in gen- erated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". psEmbedCIDPostScriptFonts yes | no If set to "no", prevents embedding of CID PostScript fonts in generated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". () 2 OSTSCRIPT_CONTRO psPaperSize width(pts) height(pts) Sets the paper size for PostScript output. The width and height parameters give the paper size in PostScript points (1 point = 1/72 inch). psPaperSize letter | legal | A4 | A3 | match Sets the paper size for PostScript output to a standard size. The default paper size is set when xpdf and pdftops are built, typically to "letter" or "A4". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. psImageableArea llx lly urx ury Sets the imageable area for PostScript output. The four inte- gers are the coordinates of the lower-left and upper-right cor- ners of the imageable region, specified in points (with the ori- gin being the lower-left corner of the paper). This defaults to the full paper size; the psPaperSize option will reset the imageable area coordinates. psCrop yes | no If set to "yes", PostScript output is cropped to the CropBox specified in the PDF file; otherwise no cropping is done. This defaults to "yes". psExpandSmaller yes | no If set to "yes", PDF pages smaller than the PostScript imageable area are expanded to fill the imageable area. Otherwise, no scalling is done on smaller pages. This defaults to "no". psShrinkLarger yes | no If set to yes, PDF pages larger than the PostScript imageable area are shrunk to fit the imageable area. Otherwise, no scal- ing is done on larger pages. This defaults to "yes". psCenter yes | no If set to yes, PDF pages smaller than the PostScript imageable area (after any scaling) are centered in the imageable area. Otherwise, they are aligned at the lower-left corner of the imageable area. This defaults to "yes". psDuplex yes | no If set to "yes", the generated PostScript will set the "Duplex" pagedevice entry. This tells duplex-capable printers to enable duplexing. This defaults to "no". psLevel level1 | level1sep | level2 | level2sep | level3 | level3Sep Sets the PostScript level to generate. This defaults to "level2". psPreload yes | no If set to "yes", PDF forms are converted to PS procedures, and image data is preloaded. This uses more memory in the Post- Script interpreter, but generates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. This defaults to "no". psOPI yes | no If set to "yes", generates PostScript OPI comments for all images and forms which have OPI information. This option is only available if the Xpdf tools were compiled with OPI support. This defaults to "no". psASCIIHex yes | no If set to "yes", the ASCIIHexEncode filter will be used instead of ASCII85Encode for binary data. This defaults to "no". psUncompressPreloadedImages yes | no If set to "yes", all preloaded images in PS files will uncom- pressed. If set to "no", the original compressed images will be used when possible. The "yes" setting is useful to work around certain buggy PostScript interpreters. This defaults to "no". psRasterResolution float Set the resolution (in dpi) for rasterized pages in PostScript output. (Pdftops will rasterize pages which use transparency.) This defaults to 300. psRasterMono yes | no If set to "yes", rasterized pages in PS files will be monochrome (8-bit gray) instead of color. This defaults to "no". psAlwaysRasterize yes | no If set to "yes", all PostScript output will be rasterized. This defaults to "no". psFile file-or-command Sets the default PostScript file or print command for xpdf. Commands start with a '|' character; anything else is a file. If the file name or command contains spaces it must be quoted. This defaults to unset, which tells xpdf to generate a name of the form .ps for a PDF file .pdf. fontDir dir See the description above, in the DISPLAY FONTS section. () 2 EXT_CONTRO textEncoding encoding-name Sets the encoding to use for text output. (This can be overrid- den with the "-enc" switch on the command line.) The encod- ing-name must be defined with the unicodeMap command (see above). This defaults to "Latin1". textEOL unix | dos | mac Sets the end-of-line convention to use for text output. The options are: unix = LF dos = CR+LF mac = CR (This can be overridden with the "-eol" switch on the command line.) The default value is based on the OS where xpdf and pdftotext were built. textPageBreaks yes | no If set to "yes", text extraction will insert page breaks (form feed characters) between pages. This defaults to "yes". textKeepTinyChars yes | no If set to "yes", text extraction will keep all characters. If set to "no", text extraction will discard tiny (smaller than 3 point) characters after the first 50000 per page, avoiding extremely slow run times for PDF files that use special fonts to do shading or cross-hatching. This defaults to "no". () 2 ISCELLANEOUS_SETTING initialZoom percentage | page | width Sets the initial zoom factor. A number specifies a zoom per- centage, where 100 means 72 dpi. You may also specify 'page', to fit the page to the window size, or 'width', to fit the page width to the window width. continuousView yes | no If set to "yes", xpdf will start in continuous view mode, i.e., with one vertical screoll bar for the whole document. This defaults to "no". enableT1lib yes | no Enables or disables use of t1lib (a Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with t1lib support. ("enableT1lib" replaces the old "t1libControl" option.) This option defaults to "yes". enableFreeType yes | no Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". enableFreeType yes | no Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". disableFreeTypeHinting yes | no If this is set to "yes", FreeType hinting will be forced off. This option defaults to "no". antialias yes | no Enables or disables font anti-aliasing in the PDF rasterizer. This option affects all font rasterizers. ("antialias" replaces the anti-aliasing control provided by the old "t1libControl" and "freetypeControl" options.) This default to "yes". vectorAntialias yes | no Enables or disables anti-aliasing of vector graphics in the PDF rasterizer. This defaults to "yes". antialiasPrinting yes | no If this is "yes", bitmaps sent to the printer will be antialiased (according to the "antialias" and "vectorAntialias" settings). If this is "no", printed bitmaps will not be antialiased. This defaults to "no". strokeAdjust yes | no Enables or disables stroke adjustment. Stroke adjustment moves horizontal and vertical lines by up to half a pixel to make them look "cleaner" when vector anti-aliasing is enabled. This defaults to "yes". screenType dispersed | clustered | stochasticClustered Sets the halftone screen type, which will be used when generat- ing a monochrome (1-bit) bitmap. The three options are dis- persed-dot dithering, clustered-dot dithering (with a round dot and 45-degree screen angle), and stochastic clustered-dot dithering. By default, "stochasticClustered" is used for reso- lutions of 300 dpi and higher, and "dispersed" is used for reso- lutions lower then 300 dpi. screenSize integer Sets the size of the (square) halftone screen threshold matrix. By default, this is 4 for dispersed-dot dithering, 10 for clus- tered-dot dithering, and 100 for stochastic clustered-dot dithering. screenDotRadius integer Sets the halftone screen dot radius. This is only used when screenType is set to stochasticClustered, and it defaults to 2. In clustered-dot mode, the dot radius is half of the screen size. Dispersed-dot dithering doesn't have a dot radius. screenGamma float Sets the halftone screen gamma correction parameter. Gamma val- ues greater than 1 make the output brighter; gamma values less than 1 make it darker. The default value is 1. screenBlackThreshold float When halftoning, all values below this threshold are forced to solid black. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 0. screenWhiteThreshold float When halftoning, all values above this threshold are forced to solid white. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 1. minLineWidth float Set the minimum line width, in device pixels. This affects the rasterizer only, not the PostScript converter (except when it uses rasterization to handle transparency). The default value is 0 (no minimum). drawAnnotations yes | no If set to "no", annotations will not be drawn or printed. The default value is "yes". overprintPreview yes | no If set to "yes", generate overprint preview output, honoring the OP/op/OPM settings in the PDF file. Ignored for non-CMYK out- put. The default value is "no". launchCommand command Sets the command executed when you click on a "launch"-type link. The intent is for the command to be a program/script which determines the file type and runs the appropriate viewer. The command line will consist of the file to be launched, fol- lowed by any parameters specified with the link. Do not use "%s" in "command". By default, this is unset, and Xpdf will simply try to execute the file (after prompting the user). urlCommand command Sets the command executed when you click on a URL link. The string "%s" will be replaced with the URL. (See the example below.) This has no default value. movieCommand command Sets the command executed when you click on a movie annotation. The string "%s" will be replaced with the movie file name. This has no default value. mapNumericCharNames yes | no If set to "yes", the Xpdf tools will attempt to map various numeric character names sometimes used in font subsets. In some cases this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "yes". mapUnknownCharNames yes | no If set to "yes", and mapNumericCharNames is set to "no", the Xpdf tools will apply a simple pass-through mapping (Unicode index = character code) for all unrecognized glyph names. (For CID fonts, setting mapNumericCharNames to "no" is unnecessary.) In some cases, this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "no". bind modifiers-key context command ... Add a key or mouse button binding. Modifiers can be zero or more of: shift- ctrl- alt- Key can be a regular ASCII character, or any one of: space tab return enter backspace insert delete home end pgup pgdn left / right / up / down (arrow keys) f1 .. f35 (function keys) mousePress1 .. mousePress7 (mouse buttons) mouseRelease1 .. mouseRelease7 (mouse buttons) Context is either "any" or a comma-separated combination of: fullScreen / window (full screen mode on/off) continuous / singlePage (continuous mode on/off) overLink / offLink (mouse over link or not) scrLockOn / scrLockOff (scroll lock on/off) The context string can include only one of each pair in the above list. Command is an Xpdf command (see the COMMANDS section of the xpdf(1) man page for details). Multiple commands are separated by whitespace. The bind command replaces any existing binding, but only if it was defined for the exact same modifiers, key, and context. All tokens (modifiers, key, context, commands) are case-sensitive. Example key bindings: # bind ctrl-a in any context to the nextPage # command bind ctrl-a any nextPage # bind uppercase B, when in continuous mode # with scroll lock on, to the reload command # followed by the prevPage command bind B continuous,scrLockOn reload prevPage See the xpdf(1) man page for more examples. unbind modifiers-key context Removes a key binding established with the bind command. This is most useful to remove default key bindings before establish- ing new ones (e.g., if the default key binding is given for "any" context, and you want to create new key bindings for mul- tiple contexts). printCommands yes | no If set to "yes", drawing commands are printed as they're exe- cuted (useful for debugging). This defaults to "no". errQuiet yes | no If set to "yes", this suppresses all error and warning messages from all of the Xpdf tools. This defaults to "no". () 2 EXAMPLES The following is a sample xpdfrc file. # from the Thai support package nameToUnicode /usr/local/share/xpdf/Thai.nameToUnicode # from the Japanese support package cidToUnicode Adobe-Japan1 /usr/local/share/xpdf/Adobe-Japan1.cidToUnicode unicodeMap JISX0208 /usr/local/share/xpdf/JISX0208.unicodeMap cMapDir Adobe-Japan1 /usr/local/share/xpdf/cmap/Adobe-Japan1 # use the Base-14 Type 1 fonts from ghostscript fontFile Times-Roman /usr/local/share/ghostscript/fonts/n021003l.pfb fontFile Times-Italic /usr/local/share/ghostscript/fonts/n021023l.pfb fontFile Times-Bold /usr/local/share/ghostscript/fonts/n021004l.pfb fontFile Times-BoldItalic /usr/local/share/ghostscript/fonts/n021024l.pfb fontFile Helvetica /usr/local/share/ghostscript/fonts/n019003l.pfb fontFile Helvetica-Oblique /usr/local/share/ghostscript/fonts/n019023l.pfb fontFile Helvetica-Bold /usr/local/share/ghostscript/fonts/n019004l.pfb fontFile Helvetica-BoldOblique /usr/local/share/ghostscript/fonts/n019024l.pfb fontFile Courier /usr/local/share/ghostscript/fonts/n022003l.pfb fontFile Courier-Oblique /usr/local/share/ghostscript/fonts/n022023l.pfb fontFile Courier-Bold /usr/local/share/ghostscript/fonts/n022004l.pfb fontFile Courier-BoldOblique /usr/local/share/ghostscript/fonts/n022024l.pfb fontFile Symbol /usr/local/share/ghostscript/fonts/s050000l.pfb fontFile ZapfDingbats /usr/local/share/ghostscript/fonts/d050000l.pfb # use the Bakoma Type 1 fonts # (this assumes they happen to be installed in /usr/local/fonts/bakoma) fontDir /usr/local/fonts/bakoma # set some PostScript options psPaperSize letter psDuplex no psLevel level2 psEmbedType1Fonts yes psEmbedTrueTypeFonts yes psFile "| lpr -Pprinter5" # assume that the PostScript printer has the Univers and # Univers-Bold fonts psResidentFont Univers Univers psResidentFont Univers-Bold Univers-Bold # set the text output options textEncoding UTF-8 textEOL unix # misc options enableT1lib yes enableFreeType yes launchCommand viewer-script urlCommand "netscape -remote 'openURL(%s)'" () 2 FILES /usr/local/etc/xpdfrc This is the default location for the system-wide configuration file. Depending on build options, it may be placed elsewhere. $HOME/.xpdfrc This is the user's configuration file. If it exists, it will be read in place of the system-wide file. () 2 AUTHOR The Xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdftoppm(1), pdfimages(1) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/pdftotext.cat0000644000076400007640000000773711622305345015210 0ustar derekndereknpdftotext(1) pdftotext(1) NAME pdftotext - Portable Document Format (PDF) to text converter (version 3.03) SYNOPSIS pdftotext [options] [PDF-file [text-file]] DESCRIPTION Pdftotext converts Portable Document Format (PDF) files to plain text. Pdftotext reads the PDF file, PDF-file, and writes a text file, text- file. If text-file is not specified, pdftotext converts file.pdf to file.txt. If text-file is '-', the text is sent to stdout. CONFIGURATION FILE Pdftotext reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftotext is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to convert. -l number Specifies the last page to convert. -layout Maintain (as best as possible) the original physical layout of the text. The default is to 'undo' physical layout (columns, hyphenation, etc.) and output the text in reading order. -fixed number Assume fixed-pitch (or tabular) text, with the specified charac- ter width (in points). This forces physical layout mode. -raw Keep the text in content stream order. This is a hack which often "undoes" column formatting, etc. Use of raw mode is no longer recommended. -htmlmeta Generate a simple HTML file, including the meta information. This simply wraps the text in
 and 
and prepends the meta headers. -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). The encoding name is case-sensitive. This defaults to "Latin1" (which is a built-in encoding). [config file: textEncoding] -eol unix | dos | mac Sets the end-of-line convention to use for text output. [config file: textEOL] -nopgbrk Don't insert page breaks (form feed characters) between pages. [config file: textPageBreaks] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) BUGS Some PDF files contain fonts whose encodings have been mangled beyond recognition. There is no way (short of OCR) to extract text from these files. EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdftotext software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdftotext(1) xpdf-3.03/doc/xpdf.cat0000644000076400007640000006445411622305345014127 0ustar derekndereknxpdf(1) xpdf(1) NAME xpdf - Portable Document Format (PDF) file viewer for X (version 3.03) SYNOPSIS xpdf [options] [PDF-file [page | +dest]] DESCRIPTION Xpdf is a viewer for Portable Document Format (PDF) files. (These are also sometimes also called 'Acrobat' files, from the name of Adobe's PDF software.) Xpdf runs under the X Window System on UNIX, VMS, and OS/2. To run xpdf, simply type: xpdf file.pdf where file.pdf is your PDF file. The file name can be followed by a number specifying the page which should be displayed first, e.g.: xpdf file.pdf 18 You can also give a named destination, prefixed with '+' in place of the page number. (This is only useful with PDF files that provide named destination targets.) You can also start xpdf without opening any files: xpdf CONFIGURATION FILE Xpdf reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when xpdf is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands or X resources. These are listed in square brackets with the description of the corresponding command line option. -g geometry Set the initial window geometry. (-geometry is equivalent.) [X resource: xpdf.geometry] -title title Set the window title. By default, the title will be "xpdf: foo.pdf". [X resource: xpdf.title] -cmap Install a private colormap. This is ignored on TrueColor visu- als. [X resource: xpdf.installCmap] -rgb number Set the size of largest RGB cube xpdf will try to allocate. The default is 5 (for a 5x5x5 cube); set to a smaller number to con- serve color table entries. This is ignored with private col- ormaps and on TrueColor visuals. [X resource: xpdf.rgbCubeSize] -rv Set reverse video mode. This reverses the colors of everything except images. It may not always produce great results for PDF files which do weird things with color. This also causes the paper color to default to black. [X resource: xpdf.reverseV- ideo] -papercolor color Set the "paper color", i.e., the background of the page display. This will not work too well with PDF files that do things like filling in white behind the text. [X resource: xpdf.paperColor] -mattecolor color Set the matte color, i.e., the color used for background outside the actual page area. (There is a separate setting, xpdf.fullScreenMatteColor, for full-screen mode.) [X resource: xpdf.matteColor] -z zoom Set the initial zoom factor. A number specifies a zoom percent- age, where 100 means 72 dpi. You may also specify 'page', to fit the page to the window size, or 'width', to fit the page width to the window width. [config file: initialZoom; or X resource: xpdf.initialZoom] -cont Start in continuous view mode, i.e., with one vertical scroll bar for the whole document. [config file: continuousView] -t1lib yes | no Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". [config file: enableT1lib] -freetype yes | no Enable or disable FreeType (a TrueType / Type 1 font raster- izer). This defaults to "yes". [config file: enableFreeType] -aa yes | no Enable or disable font anti-aliasing. This defaults to "yes". [config file: antialias] -aaVector yes | no Enable or disable vector anti-aliasing. This defaults to "yes". [config file: vectorAntialias] -ps PS-file Set the default file name for PostScript output (i.e., the name which will appear in the print dialog). This can also be of the form '|command' to pipe the PostScript through a command. [con- fig file: psFile] -paper size Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. [config file: psPaperSize] -paperw size Set the paper width, in points. [config file: psPaperSize] -paperh size Set the paper height, in points. [config file: psPaperSize] -level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. [config file: psLevel] -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [con- fig file: textEncoding] -eol unix | dos | mac Sets the end-of-line convention to use for text output. [config file: textEOL] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -fullscreen Open xpdf in full-screen mode, useful for presentations. -remote name Start/contact xpdf remote server with specified name (see the REMOTE SERVER MODE section below). -exec command Execute a command (see the COMMANDS section below) in an xpdf remote server window (with -remote only). -reload Reload xpdf remote server window (with -remote only). -raise Raise xpdf remote server window (with -remote only). -quit Kill xpdf remote server (with -remote only). -cmd Print commands as they're executed (useful for debugging). [config file: printCommands] -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) Several other standard X options and resources will work as expected: -display display [X resource: xpdf.display] -fg color (-foreground is equivalent.) [X resource: xpdf*Foreground] -bg color (-background is equivalent.) [X resource: xpdf*Background] -font font (-fn is equivalent.) [X resource: xpdf*fontList] The color and font options only affect the user interface elements, not the PDF display (the 'paper'). The following X resources do not have command line option equivalents: xpdf.toolTipEnable Enables (if set to true) or disables (if set to false) the tool- tips on the toolbar buttons. xpdf.fullScreenMatteColor Sets the matte color to be used in full-screen mode. The default setting is "black". CONTROLS On-screen controls, at the bottom of the xpdf window left/right arrow buttons Move to the previous/next page. double left/right arrow buttons Move backward or forward by ten pages. dashed left/right arrow buttons Move backward or forward along the history path. 'Page' entry box Move to a specific page number. Click in the box to activate it, type the page number, then hit return. zoom popup menu Change the zoom factor (see the description of the -z option above). binoculars button Find a text string. print button Bring up a dialog for generating a PostScript file. The dialog has options to set the pages to be printed and the PostScript file name. The file name can be '-' for stdout or '|command' to pipe the PostScript through a command, e.g., '|lpr'. '?' button Bring up the 'about xpdf' window. link info The space between the '?' and 'Quit' buttons is used to show the URL or external file name when the mouse is over a link. 'Quit' button Quit xpdf. Menu Pressing the right mouse button will post a popup menu with the follow- ing commands: Open... Open a new PDF file via a file requester. Open in new window... Create a new window and open a new PDF file via a file requester. Reload Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. Save as... Save the current file via a file requester. Continuous view Toggles between single page and continuous view modes. Rotate counterclockwise Rotate the page 90 degrees counterclockwise. Rotate clockwise Rotate the page 90 degrees clockwise. The two rotate commands are intended primarily for PDF files where the rotation isn't correctly specified in the file. Zoom to selection Zoom in to the currently selected rectangle. Close Close the current window. If this is the only open window, the document is closed, but the window is left open (i.e., this menu command won't quit xpdf). Quit Quit xpdf. Outline If the PDF contains an outline (a.k.a., bookmarks), there will be an outline pane on the left side of the window. The width of the outline pane is adjustable with a vertical split bar via the knob near its bot- tom end. Text selection Dragging the mouse with the left button held down will highlight an arbitrary rectangle. Any text inside this rectangle will be copied to the X selection buffer. Links Clicking on a hyperlink will jump to the link's destination. A link to another PDF document will make xpdf load that document. A 'launch' link to an executable program will display a dialog, and if you click 'ok', execute the program. URL links call an external command (see the WEB BROWSERS section below). Panning Dragging the mouse with the middle button held down pans the window. Key bindings o Open a new PDF file via a file requester. r Reload the current PDF file. Note that Xpdf will reload the file automatically (on a page change or redraw) if it has changed since it was last loaded. control-L Redraw the current page. control-W Close the current window. f or control-F Find a text string. control-G Find next occurrence. control-P Print. n Move to the next page. Scrolls to the top of the page, unless scroll lock is turned on. p Move to the previous page. Scrolls to the top of the page, unless scroll lock is turned on. or or Scroll down on the current page; if already at bottom, move to next page. or or or Scroll up on the current page; if already at top, move to previ- ous page. v Move forward along the history path. b Move backward along the history path. Scroll to top of current page. Scroll to bottom of current page. control- Scroll to first page of document. control- Scroll to last page of document. arrows Scroll the current page. g Activate the page number text field ("goto page"). 0 Set the zoom factor to 125%. + Zoom in (increment the zoom factor by 1). - Zoom out (decrement the zoom factor by 1). z Set the zoom factor to 'page' (fit page to window). w Set the zoom factor to 'width' (fit page width to window). alt-F Toggle full-screen mode. q Quit xpdf. WEB BROWSERS If you want to run xpdf automatically from netscape or mosaic (and probably other browsers) when you click on a link to a PDF file, you need to edit (or create) the files .mime.types and .mailcap in your home directory. In .mime.types add the line: application/pdf pdf In .mailcap add the lines: # Use xpdf to view PDF files. application/pdf; xpdf -q %s Make sure that xpdf is on your executable search path. When you click on a URL link in a PDF file, xpdf will execute the com- mand specified by the urlCommand config file option, replacing an occurrence of '%s' with the URL. For example, to call netscape with the URL, add this line to your config file: urlCommand "netscape -remote 'openURL(%s)'" COMMANDS Xpdf's key and mouse bindings are user-configurable, using the bind and unbind options in the config file (see xpdfrc(5)). The bind command allows you to bind a key or mouse button to a sequence of one or more commands. Available Commands The following commands are supported: gotoPage(page) Go to the specified page. gotoPageNoScroll(page) Go to the specified page, with the current relative scroll posi- tion. gotoDest(dest) Go to a named destination. gotoLastPage Go to the last page in the PDF file. gotoLastPageNoScroll Go to the last page in the PDF file, with the current relative scroll position. nextPage Go to the next page. nextPageNoScroll Go to the next page, with the current relative scroll position. prevPage Go to the previous page. prevPageNoScroll Go to the previous page, with the current relative scroll posi- tion. pageUp Scroll up by one screenful. pageDown Scroll down by one screenful. scrollLeft(n) Scroll left by n pixels. scrollRight(n) Scroll right by n pixels. scrollUp(n) Scroll up by n pixels. scrollDown(n) Scroll down by n pixels. scrollUpPrevPage(n) Scroll up by n pixels, moving to the previous page if appropri- ate. scrollDownPrevPage(n) Scroll down by n pixels, moving to the next page if appropriate. scrollToTopEdge Scroll to the top edge of the current page, with no horizontal movement. scrollToBottomEdge Scroll to the bottom edge of the current page, with no horizon- tal movement. scrollToLeftEdge Scroll to the left edge of the current page, with no vertical movement. scrollToRightEdge Scroll to the right edge of the current page, with no vertical movement. scrollToTopLeft Scroll to the top-left corner of the current page. scrollToBottomRight Scroll to the bottom-right corner of the current page. goForward Move forward along the history path. goBackward Move backward along the history path. zoomPercent(z) Set the zoom factor to z%. zoomFitPage Set the zoom factor to fit-page. zoomFitWidth Set the zoom factor to fit-width. zoomIn Zoom in - go to the next higher zoom factor. zoomOut Zoom out - go the next lower zoom factor. rotateCW Rotate the page 90 degrees clockwise. rotateCCW Rotate the page 90 degrees counterclockwise. setSelection(pg,ulx,uly,lrx,lry) Set the selection to the specified coordinates on the specified page. continuousMode Go to continuous view mode. singlePageMode Go to single-page view mode. toggleContinuousMode Toggle between continuous and single page view modes. fullScreenMode Go to full-screen mode. windowMode Go to window (non-full-screen) mode. toggleFullScreenMode Toggle between full-screen and window modes. open Open a PDF file in this window, using the open dialog. openInNewWin Open a PDF file in a new window, using the open dialog. openFile(file) Open a specified PDF file in this window. openFileInNewWin(file) Open a specified PDF file in a new window. openFileAtDest(file,dest) Open a specified PDF file in this window and go to a named des- tination. openFileAtDestInNewWin(file,dest) Open a specified PDF file in a new window and go to a named des- tination. reload Reload the current PDF file. redraw Redraw the window. raise Raise the window to the front. closeWindow Close the window. run(external-command-string) Run an external command. The following escapes are allowed in the command string: %f => PDF file name (or an empty string if no file is open) %b => PDF file base name, i.e., file name minus the extension (or an empty string if no file is open) %u => link URL (or an empty string if not over a URL link) %p => current page number (or an empty string if no file is open) %x => selection upper-left x coordinate (or 0 if there is no selection) %y => selection upper-left y coordinate (or 0 if there is no selection) %X => selection lower-right x coordinate (or 0 if there is no selection) %Y => selection lower-right y coordinate (or 0 if there is no selection) %i => page containing the mouse pointer %j => x coordinate of the mouse pointer %k => y coordinate of the mouse pointer %% => % openOutline Open the outline pane. closeOutline Close the outline pane. toggleOutline Toggle the outline pane between open and closed. scrollOutlineDown(n) Scroll the outline down by n increments. scrollOutlineUp(n) Scroll the outline up by n increments. focusToDocWin Set the keyboard focus to the main document window. focusToPageNum Set the keyboard focus to the page number text box. find Open the 'find' dialog. findNext Finds the next occurrence of the search string (no dialog). print Open the 'print' dialog. about Open the 'about' dialog. quit Quit from xpdf. The following commands depend on the current mouse position: startSelection Start a selection, which will be extended as the mouse moves. endSelection End a selection. startPan Start a pan, which will scroll the document as the mouse moves endPan End a pan. postPopupMenu Display the popup menu. followLink Follow a hyperlink (does nothing if the mouse is not over a link). followLinkInNewWin Follow a hyperlink, opening PDF files in a new window (does nothing if the mouse is not over a link). For links to non-PDF files, this command is identical to followLink. followLinkNoSel Same as followLink, but does nothing if there is a non-empty selection. (This is useful as a mouse button binding.) followLinkInNewWinNoSel Same as followLinkInNewWin, but does nothing if there is a non- empty selection. (This is useful as a mouse button binding.) Default Bindings The default mouse bindings are as follows: bind mousePress1 any startSelection bind mouseRelease1 any endSelection followLinkNoSel bind mousePress2 any startPan bind mouseRelease2 any endPan bind mousePress3 any postPopupMenu bind mousePress4 any scrollUpPrevPage(16) bind mousePress5 any scrollDownNextPage(16) bind mousePress6 any scrollLeft(16) bind mousePress7 any scrollRight(16) The default key bindings are as follows: bind ctrl-home any gotoPage(1) bind home any scrollToTopLeft bind ctrl-end any gotoLastPage bind end any scrollToBottomRight bind pgup any pageUp bind backspace any pageUp bind delete any pageUp bind pgdn any pageDown bind space any pageDown bind left any scrollLeft(16) bind right any scrollRight(16) bind up any scrollUp(16) bind down any scrollDown(16) bind o any open bind O any open bind r any reload bind R any reload bind f any find bind F any find bind ctrl-f any find bind ctrl-g any findNext bind ctrl-p any print bind n scrLockOff nextPage bind N scrLockOff nextPage bind n scrLockOn nextPageNoScroll bind N scrLockOn nextPageNoScroll bind p scrLockOff prevPage bind P scrLockOff prevPage bind p scrLockOn prevPageNoScroll bind P scrLockOn prevPageNoScroll bind v any goForward bind b any goBackward bind g any focusToPageNum bind 0 any zoomPercent(125) bind + any zoomIn bind - any zoomOut bind z any zoomFitPage bind w any zoomFitWidth bind alt-f any toggleFullScreenMode bind ctrl-l any redraw bind ctrl-w any closeWindow bind ? any about bind q any quit bind Q any quit Previous versions of xpdf included a "viKeys" X resource. It is no longer available, but the following bindings are equivalent: bind h any scrollLeft(16) bind l any scrollRight(16) bind k any scrollUp(16) bind j any scrollDown(16) REMOTE SERVER MODE Xpdf can be started in remote server mode by specifying a server name (in addition to the file name and page number). For example: xpdf -remote myServer file.pdf If there is currently no xpdf running in server mode with the name 'myServer', a new xpdf window will be opened. If another command: xpdf -remote myServer another.pdf 9 is issued, a new copy of xpdf will not be started. Instead, the first xpdf (the server) will load another.pdf and display page nine. If the file name is the same: xpdf -remote myServer another.pdf 4 the xpdf server will simply display the specified page. The -raise option tells the server to raise its window; it can be spec- ified with or without a file name and page number. The -quit option tells the server to close its window and exit. EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 xpdf(1) xpdf-3.03/doc/xpdfrc.cat0000644000076400007640000007152011622305345014444 0ustar derekndereknxpdfrc(5) xpdfrc(5) NAME xpdfrc - configuration file for Xpdf tools (version 3.03) DESCRIPTION All of the Xpdf tools read a single configuration file. If you have a .xpdfrc file in your home directory, it will be read. Otherwise, a system-wide configuration file will be read from /usr/local/etc/xpdfrc, if it exists. (This is its default location; depending on build options, it may be placed elsewhere.) On Win32 systems, the xpdfrc file should be placed in the same directory as the executables. The xpdfrc file consists of a series of configuration options, one per line. Blank lines and lines starting with a '#' (comments) are ignored. The following sections list all of the configuration options, sorted into functional groups. There is an examples section at the end. INCLUDE FILES include config-file Includes the specified config file. The effect of this is equivalent to inserting the contents of config-file directly into the parent config file in place of the include command. Config files can be nested arbitrarily deeply. CHARACTER MAPPING nameToUnicode map-file Specifies a file with the mapping from character names to Uni- code. This is used to handle PDF fonts that have valid encod- ings but no ToUnicode entry. Each line of a nameToUnicode file looks like this: hex-string name The hex-string is the Unicode (UCS-2) character index, and name is the corresponding character name. Multiple nameToUnicode files can be used; if a character name is given more than once, the code in the last specified file is used. There is a built- in default nameToUnicode table with all of Adobe's standard character names. cidToUnicode registry-ordering map-file Specifies the file with the mapping from character collection to Unicode. Each line of a cidToUnicode file represents one char- acter: hex-string The hex-string is the Unicode (UCS-2) index for that character. The first line maps CID 0, the second line CID 1, etc. File size is determined by size of the character collection. Only one file is allowed per character collection; the last specified file is used. There are no built-in cidToUnicode mappings. unicodeToUnicode font-name-substring map-file This is used to work around PDF fonts which have incorrect Uni- code information. It specifies a file which maps from the given (incorrect) Unicode indexes to the correct ones. The mapping will be used for any font whose name contains font-name-sub- string. Each line of a unicodeToUnicode file represents one Unicode character: in-hex out-hex1 out-hex2 ... The in-hex field is an input (incorrect) Unicode index, and the rest of the fields are one or more output (correct) Unicode indexes. Each occurrence of in-hex will be converted to the specified output sequence. unicodeMap encoding-name map-file Specifies the file with mapping from Unicode to encoding-name. These encodings are used for text output (see below). Each line of a unicodeMap file represents a range of one or more Unicode characters which maps linearly to a range in the output encod- ing: in-start-hex in-end-hex out-start-hex Entries for single characters can be abbreviated to: in-hex out-hex The in-start-hex and in-end-hex fields (or the single in-hex field) specify the Unicode range. The out-start-hex field (or the out-hex field) specifies the start of the output encoding range. The length of the out-start-hex (or out-hex) string determines the length of the output characters (e.g., UTF-8 uses different numbers of bytes to represent characters in different ranges). Entries must be given in increasing Unicode order. Only one file is allowed per encoding; the last specified file is used. The Latin1, ASCII7, Symbol, ZapfDingbats, UTF-8, and UCS-2 encodings are predefined. cMapDir registry-ordering dir Specifies a search directory, dir, for CMaps for the reg- istry-ordering character collection. There can be multiple directories for a particular collection. There are no default CMap directories. toUnicodeDir dir Specifies a search directory, dir, for ToUnicode CMaps. There can be multiple ToUnicode directories. There are no default ToUnicode directories. GENERAL FONT CONFIGURATION fontFile PDF-font-name font-file Maps a PDF font, PDF-font-name, to a font for display or Post- Script output. The font file, font-file, can be any type allowed in a PDF file. This command can be used for 8-bit or 16-bit (CID) fonts. fontDir dir Specifies a search directory for font files. There can be mul- tiple fontDir commands; all of the specified directories will be searched in order. The font files can be Type 1 (.pfa or .pfb) or TrueType (.ttf or .ttc); other files in the directory will be ignored. The font file name (not including the extension) must exactly match the PDF font name. This search is performed if the font name doesn't match any of the fonts declared with the fontFile command. There are no default fontDir directories. fontFileCC registry-ordering font-file Maps the registry-ordering character collection to a font for display or PostScript output. This mapping is used if the font name doesn't match any of the fonts declared with the fontFile, fontDir, psResidentFont16, or psResidentFontCC commands. POSTSCRIPT FONT CONFIGURATION psFontPassthrough yes | no If set to "yes", pass 8-bit font names through to the PostScript output without substitution. Fonts which are not embedded in the PDF file are expected to be available on the printer. This defaults to "no". psResidentFont PDF-font-name PS-font-name When the 8-bit font PDF-font-name is used (without embedding) in a PDF file, it will be translated to the PostScript font PS-font-name, which is assumed to be resident in the printer. Typically, PDF-font-name and PS-font-name are the same. By default, only the Base-14 fonts are assumed to be resident. psResidentFont16 PDF-font-name wMode PS-font-name encoding When the 16-bit (CID) font PDF-font-name with writing mode wMode is used (without embedding) in a PDF file, it will be translated to the PostScript font PS-font-name, which is assumbed to be resident in the printer. The writing mode must be either 'H' for horizontal or 'V' for vertical. The resident font is assumed to use the specified encoding (which must have been defined with the unicodeMap command). psResidentFontCC registry-ordering wMode PS-font-name encoding When a 16-bit (CID) font using the registry-ordering character collection and wMode writing mode is used (without embedding) in a PDF file, the PostScript font, PS-font-name, is substituted for it. The substituted font is assumbed to be resident in the printer. The writing mode must be either 'H' for horizontal or 'V' for vertical. The resident font is assumed to use the spec- ified encoding (which must have been defined with the unicodeMap command). psEmbedType1Fonts yes | no If set to "no", prevents embedding of Type 1 fonts in generated PostScript. This defaults to "yes". psEmbedTrueTypeFonts yes | no If set to "no", prevents embedding of TrueType fonts in gener- ated PostScript. This defaults to "yes". psEmbedCIDTrueTypeFonts yes | no If set to "no", prevents embedding of CID TrueType fonts in gen- erated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". psEmbedCIDPostScriptFonts yes | no If set to "no", prevents embedding of CID PostScript fonts in generated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". POSTSCRIPT CONTROL psPaperSize width(pts) height(pts) Sets the paper size for PostScript output. The width and height parameters give the paper size in PostScript points (1 point = 1/72 inch). psPaperSize letter | legal | A4 | A3 | match Sets the paper size for PostScript output to a standard size. The default paper size is set when xpdf and pdftops are built, typically to "letter" or "A4". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. psImageableArea llx lly urx ury Sets the imageable area for PostScript output. The four inte- gers are the coordinates of the lower-left and upper-right cor- ners of the imageable region, specified in points (with the ori- gin being the lower-left corner of the paper). This defaults to the full paper size; the psPaperSize option will reset the imageable area coordinates. psCrop yes | no If set to "yes", PostScript output is cropped to the CropBox specified in the PDF file; otherwise no cropping is done. This defaults to "yes". psExpandSmaller yes | no If set to "yes", PDF pages smaller than the PostScript imageable area are expanded to fill the imageable area. Otherwise, no scalling is done on smaller pages. This defaults to "no". psShrinkLarger yes | no If set to yes, PDF pages larger than the PostScript imageable area are shrunk to fit the imageable area. Otherwise, no scal- ing is done on larger pages. This defaults to "yes". psCenter yes | no If set to yes, PDF pages smaller than the PostScript imageable area (after any scaling) are centered in the imageable area. Otherwise, they are aligned at the lower-left corner of the imageable area. This defaults to "yes". psDuplex yes | no If set to "yes", the generated PostScript will set the "Duplex" pagedevice entry. This tells duplex-capable printers to enable duplexing. This defaults to "no". psLevel level1 | level1sep | level2 | level2sep | level3 | level3Sep Sets the PostScript level to generate. This defaults to "level2". psPreload yes | no If set to "yes", PDF forms are converted to PS procedures, and image data is preloaded. This uses more memory in the Post- Script interpreter, but generates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. This defaults to "no". psOPI yes | no If set to "yes", generates PostScript OPI comments for all images and forms which have OPI information. This option is only available if the Xpdf tools were compiled with OPI support. This defaults to "no". psASCIIHex yes | no If set to "yes", the ASCIIHexEncode filter will be used instead of ASCII85Encode for binary data. This defaults to "no". psUncompressPreloadedImages yes | no If set to "yes", all preloaded images in PS files will uncom- pressed. If set to "no", the original compressed images will be used when possible. The "yes" setting is useful to work around certain buggy PostScript interpreters. This defaults to "no". psRasterResolution float Set the resolution (in dpi) for rasterized pages in PostScript output. (Pdftops will rasterize pages which use transparency.) This defaults to 300. psRasterMono yes | no If set to "yes", rasterized pages in PS files will be monochrome (8-bit gray) instead of color. This defaults to "no". psAlwaysRasterize yes | no If set to "yes", all PostScript output will be rasterized. This defaults to "no". psFile file-or-command Sets the default PostScript file or print command for xpdf. Commands start with a '|' character; anything else is a file. If the file name or command contains spaces it must be quoted. This defaults to unset, which tells xpdf to generate a name of the form .ps for a PDF file .pdf. fontDir dir See the description above, in the DISPLAY FONTS section. TEXT CONTROL textEncoding encoding-name Sets the encoding to use for text output. (This can be overrid- den with the "-enc" switch on the command line.) The encod- ing-name must be defined with the unicodeMap command (see above). This defaults to "Latin1". textEOL unix | dos | mac Sets the end-of-line convention to use for text output. The options are: unix = LF dos = CR+LF mac = CR (This can be overridden with the "-eol" switch on the command line.) The default value is based on the OS where xpdf and pdftotext were built. textPageBreaks yes | no If set to "yes", text extraction will insert page breaks (form feed characters) between pages. This defaults to "yes". textKeepTinyChars yes | no If set to "yes", text extraction will keep all characters. If set to "no", text extraction will discard tiny (smaller than 3 point) characters after the first 50000 per page, avoiding extremely slow run times for PDF files that use special fonts to do shading or cross-hatching. This defaults to "no". MISCELLANEOUS SETTINGS initialZoom percentage | page | width Sets the initial zoom factor. A number specifies a zoom per- centage, where 100 means 72 dpi. You may also specify 'page', to fit the page to the window size, or 'width', to fit the page width to the window width. continuousView yes | no If set to "yes", xpdf will start in continuous view mode, i.e., with one vertical screoll bar for the whole document. This defaults to "no". enableT1lib yes | no Enables or disables use of t1lib (a Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with t1lib support. ("enableT1lib" replaces the old "t1libControl" option.) This option defaults to "yes". enableFreeType yes | no Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". enableFreeType yes | no Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". disableFreeTypeHinting yes | no If this is set to "yes", FreeType hinting will be forced off. This option defaults to "no". antialias yes | no Enables or disables font anti-aliasing in the PDF rasterizer. This option affects all font rasterizers. ("antialias" replaces the anti-aliasing control provided by the old "t1libControl" and "freetypeControl" options.) This default to "yes". vectorAntialias yes | no Enables or disables anti-aliasing of vector graphics in the PDF rasterizer. This defaults to "yes". antialiasPrinting yes | no If this is "yes", bitmaps sent to the printer will be antialiased (according to the "antialias" and "vectorAntialias" settings). If this is "no", printed bitmaps will not be antialiased. This defaults to "no". strokeAdjust yes | no Enables or disables stroke adjustment. Stroke adjustment moves horizontal and vertical lines by up to half a pixel to make them look "cleaner" when vector anti-aliasing is enabled. This defaults to "yes". screenType dispersed | clustered | stochasticClustered Sets the halftone screen type, which will be used when generat- ing a monochrome (1-bit) bitmap. The three options are dis- persed-dot dithering, clustered-dot dithering (with a round dot and 45-degree screen angle), and stochastic clustered-dot dithering. By default, "stochasticClustered" is used for reso- lutions of 300 dpi and higher, and "dispersed" is used for reso- lutions lower then 300 dpi. screenSize integer Sets the size of the (square) halftone screen threshold matrix. By default, this is 4 for dispersed-dot dithering, 10 for clus- tered-dot dithering, and 100 for stochastic clustered-dot dithering. screenDotRadius integer Sets the halftone screen dot radius. This is only used when screenType is set to stochasticClustered, and it defaults to 2. In clustered-dot mode, the dot radius is half of the screen size. Dispersed-dot dithering doesn't have a dot radius. screenGamma float Sets the halftone screen gamma correction parameter. Gamma val- ues greater than 1 make the output brighter; gamma values less than 1 make it darker. The default value is 1. screenBlackThreshold float When halftoning, all values below this threshold are forced to solid black. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 0. screenWhiteThreshold float When halftoning, all values above this threshold are forced to solid white. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 1. minLineWidth float Set the minimum line width, in device pixels. This affects the rasterizer only, not the PostScript converter (except when it uses rasterization to handle transparency). The default value is 0 (no minimum). drawAnnotations yes | no If set to "no", annotations will not be drawn or printed. The default value is "yes". overprintPreview yes | no If set to "yes", generate overprint preview output, honoring the OP/op/OPM settings in the PDF file. Ignored for non-CMYK out- put. The default value is "no". launchCommand command Sets the command executed when you click on a "launch"-type link. The intent is for the command to be a program/script which determines the file type and runs the appropriate viewer. The command line will consist of the file to be launched, fol- lowed by any parameters specified with the link. Do not use "%s" in "command". By default, this is unset, and Xpdf will simply try to execute the file (after prompting the user). urlCommand command Sets the command executed when you click on a URL link. The string "%s" will be replaced with the URL. (See the example below.) This has no default value. movieCommand command Sets the command executed when you click on a movie annotation. The string "%s" will be replaced with the movie file name. This has no default value. mapNumericCharNames yes | no If set to "yes", the Xpdf tools will attempt to map various numeric character names sometimes used in font subsets. In some cases this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "yes". mapUnknownCharNames yes | no If set to "yes", and mapNumericCharNames is set to "no", the Xpdf tools will apply a simple pass-through mapping (Unicode index = character code) for all unrecognized glyph names. (For CID fonts, setting mapNumericCharNames to "no" is unnecessary.) In some cases, this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "no". bind modifiers-key context command ... Add a key or mouse button binding. Modifiers can be zero or more of: shift- ctrl- alt- Key can be a regular ASCII character, or any one of: space tab return enter backspace insert delete home end pgup pgdn left / right / up / down (arrow keys) f1 .. f35 (function keys) mousePress1 .. mousePress7 (mouse buttons) mouseRelease1 .. mouseRelease7 (mouse buttons) Context is either "any" or a comma-separated combination of: fullScreen / window (full screen mode on/off) continuous / singlePage (continuous mode on/off) overLink / offLink (mouse over link or not) scrLockOn / scrLockOff (scroll lock on/off) The context string can include only one of each pair in the above list. Command is an Xpdf command (see the COMMANDS section of the xpdf(1) man page for details). Multiple commands are separated by whitespace. The bind command replaces any existing binding, but only if it was defined for the exact same modifiers, key, and context. All tokens (modifiers, key, context, commands) are case-sensitive. Example key bindings: # bind ctrl-a in any context to the nextPage # command bind ctrl-a any nextPage # bind uppercase B, when in continuous mode # with scroll lock on, to the reload command # followed by the prevPage command bind B continuous,scrLockOn reload prevPage See the xpdf(1) man page for more examples. unbind modifiers-key context Removes a key binding established with the bind command. This is most useful to remove default key bindings before establish- ing new ones (e.g., if the default key binding is given for "any" context, and you want to create new key bindings for mul- tiple contexts). printCommands yes | no If set to "yes", drawing commands are printed as they're exe- cuted (useful for debugging). This defaults to "no". errQuiet yes | no If set to "yes", this suppresses all error and warning messages from all of the Xpdf tools. This defaults to "no". EXAMPLES The following is a sample xpdfrc file. # from the Thai support package nameToUnicode /usr/local/share/xpdf/Thai.nameToUnicode # from the Japanese support package cidToUnicode Adobe-Japan1 /usr/local/share/xpdf/Adobe-Japan1.cidToUnicode unicodeMap JISX0208 /usr/local/share/xpdf/JISX0208.unicodeMap cMapDir Adobe-Japan1 /usr/local/share/xpdf/cmap/Adobe-Japan1 # use the Base-14 Type 1 fonts from ghostscript fontFile Times-Roman /usr/local/share/ghostscript/fonts/n021003l.pfb fontFile Times-Italic /usr/local/share/ghostscript/fonts/n021023l.pfb fontFile Times-Bold /usr/local/share/ghostscript/fonts/n021004l.pfb fontFile Times-BoldItalic /usr/local/share/ghostscript/fonts/n021024l.pfb fontFile Helvetica /usr/local/share/ghostscript/fonts/n019003l.pfb fontFile Helvetica-Oblique /usr/local/share/ghostscript/fonts/n019023l.pfb fontFile Helvetica-Bold /usr/local/share/ghostscript/fonts/n019004l.pfb fontFile Helvetica-BoldOblique /usr/local/share/ghostscript/fonts/n019024l.pfb fontFile Courier /usr/local/share/ghostscript/fonts/n022003l.pfb fontFile Courier-Oblique /usr/local/share/ghostscript/fonts/n022023l.pfb fontFile Courier-Bold /usr/local/share/ghostscript/fonts/n022004l.pfb fontFile Courier-BoldOblique /usr/local/share/ghostscript/fonts/n022024l.pfb fontFile Symbol /usr/local/share/ghostscript/fonts/s050000l.pfb fontFile ZapfDingbats /usr/local/share/ghostscript/fonts/d050000l.pfb # use the Bakoma Type 1 fonts # (this assumes they happen to be installed in /usr/local/fonts/bakoma) fontDir /usr/local/fonts/bakoma # set some PostScript options psPaperSize letter psDuplex no psLevel level2 psEmbedType1Fonts yes psEmbedTrueTypeFonts yes psFile "| lpr -Pprinter5" # assume that the PostScript printer has the Univers and # Univers-Bold fonts psResidentFont Univers Univers psResidentFont Univers-Bold Univers-Bold # set the text output options textEncoding UTF-8 textEOL unix # misc options enableT1lib yes enableFreeType yes launchCommand viewer-script urlCommand "netscape -remote 'openURL(%s)'" FILES /usr/local/etc/xpdfrc This is the default location for the system-wide configuration file. Depending on build options, it may be placed elsewhere. $HOME/.xpdfrc This is the user's configuration file. If it exists, it will be read in place of the system-wide file. AUTHOR The Xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdftoppm(1), pdfimages(1) http://www.foolabs.com/xpdf/ 15 August 2011 xpdfrc(5) xpdf-3.03/doc/pdfinfo.10000644000076400007640000000626411622305345014177 0ustar dereknderekn.\" Copyright 1999-2011 Glyph & Cog, LLC .TH pdfinfo 1 "15 August 2011" .SH NAME pdfinfo \- Portable Document Format (PDF) document information extractor (version 3.03) .SH SYNOPSIS .B pdfinfo [options] .RI [ PDF-file ] .SH DESCRIPTION .B Pdfinfo prints the contents of the \'Info' dictionary (plus some other useful information) from a Portable Document Format (PDF) file. .PP The \'Info' dictionary contains the following values: .PP .RS title .RE .RS subject .RE .RS keywords .RE .RS author .RE .RS creator .RE .RS producer .RE .RS creation date .RE .RS modification date .RE .PP In addition, the following information is printed: .PP .RS tagged (yes/no) .RE .RS form (AcroForm / XFA / none) .RE .RS page count .RE .RS encrypted flag (yes/no) .RE .RS print and copy permissions (if encrypted) .RE .RS page size .RE .RS file size .RE .RS linearized (yes/no) .RE .RS PDF version .RE .RS metadata (only if requested) .RE .SH CONFIGURATION FILE Pdfinfo reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to examine. If multiple pages are requested using the "\-f" and "\-l" options, the size of each requested page (and, optionally, the bounding boxes for each requested page) are printed. Otherwise, only page one is examined. .TP .BI \-l " number" Specifies the last page to examine. .TP .B \-box Prints the page box bounding boxes: MediaBox, CropBox, BleedBox, TrimBox, and ArtBox. .TP .B \-meta Prints document-level metadata. (This is the "Metadata" stream from the PDF file's Catalog object.) .TP .B \-rawdates Prints the raw (undecoded) date strings, directly from the PDF file. .TP .BI \-enc " encoding-name" Sets the encoding to use for text output. The .I encoding\-name must be defined with the unicodeMap command (see .BR xpdfrc (5)). This defaults to "Latin1" (which is a built-in encoding). .RB "[config file: " textEncoding ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdffonts.10000644000076400007640000000565611622305345014401 0ustar dereknderekn.\" Copyright 1999-2011 Glyph & Cog, LLC .TH pdffonts 1 "15 August 2011" .SH NAME pdffonts \- Portable Document Format (PDF) font analyzer (version 3.03) .SH SYNOPSIS .B pdffonts [options] .RI [ PDF-file ] .SH DESCRIPTION .B Pdffonts lists the fonts used in a Portable Document Format (PDF) file along with various information for each font. .PP The following information is listed for each font: .TP .B name the font name, exactly as given in the PDF file (potentially including a subset prefix) .TP .B type the font type -- see below for details .TP .B emb "yes" if the font is embedded in the PDF file .TP .B sub "yes" if the font is a subset .TP .B uni "yes" if there is an explicit "ToUnicode" map in the PDF file (the absence of a ToUnicode map doesn't necessarily mean that the text can't be converted to Unicode) .TP .B object ID the font dictionary object ID (number and generation) .PP PDF files can contain the following types of fonts: .PP .RS Type 1 .RE .RS Type 1C -- aka Compact Font Format (CFF) .RE .RS Type 1C (OT) -- OpenType with 8-bit CFF data .RE .RS Type 3 .RE .RS TrueType .RE .RS TrueType (OT) -- OpenType with 8-bit TrueType data .RE .RS CID Type 0 -- 16-bit font with no specified type .RE .RS CID Type 0C -- 16-bit PostScript CFF font .RE .RS CID Type 0C (OT) -- OpenType with CID CFF data .RE .RS CID TrueType -- 16-bit TrueType font .RE .RS CID TrueType (OT) -- OpenType with CID TrueType data .RE .SH CONFIGURATION FILE Pdffonts reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdffonts is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to analyze. .TP .BI \-l " number" Specifies the last page to analyze. .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdffonts software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/sample-xpdfrc0000644000076400007640000000671211622305345015156 0ustar dereknderekn#======================================================================== # # Sample xpdfrc file # # The Xpdf tools look for a config file in two places: # 1. ~/.xpdfrc # 2. in a system-wide directory, typically /usr/local/etc/xpdfrc # # This sample config file demonstrates some of the more common # configuration options. Everything here is commented out. You # should edit things (especially the file/directory paths, since # they'll likely be different on your system), and uncomment whichever # options you want to use. For complete details on config file syntax # and available options, please see the xpdfrc(5) man page. # # Also, the Xpdf language support packages each include a set of # options to be added to the xpdfrc file. # # http://www.foolabs.com/xpdf/ # #======================================================================== #----- display fonts # These map the Base-14 fonts to the Type 1 fonts that ship with # ghostscript. You'll almost certainly want to use something like # this, but you'll need to adjust this to point to wherever # ghostscript is installed on your system. (But if the fonts are # installed in a "standard" location, xpdf will find them # automatically.) #fontFile Times-Roman /usr/local/share/ghostscript/fonts/n021003l.pfb #fontFile Times-Italic /usr/local/share/ghostscript/fonts/n021023l.pfb #fontFile Times-Bold /usr/local/share/ghostscript/fonts/n021004l.pfb #fontFile Times-BoldItalic /usr/local/share/ghostscript/fonts/n021024l.pfb #fontFile Helvetica /usr/local/share/ghostscript/fonts/n019003l.pfb #fontFile Helvetica-Oblique /usr/local/share/ghostscript/fonts/n019023l.pfb #fontFile Helvetica-Bold /usr/local/share/ghostscript/fonts/n019004l.pfb #fontFile Helvetica-BoldOblique /usr/local/share/ghostscript/fonts/n019024l.pfb #fontFile Courier /usr/local/share/ghostscript/fonts/n022003l.pfb #fontFile Courier-Oblique /usr/local/share/ghostscript/fonts/n022023l.pfb #fontFile Courier-Bold /usr/local/share/ghostscript/fonts/n022004l.pfb #fontFile Courier-BoldOblique /usr/local/share/ghostscript/fonts/n022024l.pfb #fontFile Symbol /usr/local/share/ghostscript/fonts/s050000l.pfb #fontFile ZapfDingbats /usr/local/share/ghostscript/fonts/d050000l.pfb # If you need to display PDF files that refer to non-embedded fonts, # you should add one or more fontDir options to point to the # directories containing the font files. Xpdf will only look at .pfa, # .pfb, .ttf, and .ttc files in those directories (other files will # simply be ignored). #fontDir /usr/local/fonts/bakoma #----- PostScript output control # Set the default PostScript file or command. #psFile "|lpr -Pmyprinter" # Set the default PostScript paper size -- this can be letter, legal, # A4, or A3. You can also specify a paper size as width and height # (in points). #psPaperSize letter #----- text output control # Choose a text encoding for copy-and-paste and for pdftotext output. # The Latin1, ASCII7, and UTF-8 encodings are built into Xpdf. Other # encodings are available in the language support packages. #textEncoding UTF-8 # Choose the end-of-line convention for multi-line copy-and-past and # for pdftotext output. The available options are unix, mac, and dos. #textEOL unix #----- misc settings # Enable t1lib, FreeType, and anti-aliased text. #enableT1lib yes #enableFreeType yes #antialias yes # Set the command used to run a web browser when a URL hyperlink is # clicked. #launchCommand viewer-script #urlCommand "netscape -remote 'openURL(%s)'" xpdf-3.03/doc/pdfdetach.hlp0000644000076400007640000000702611622305345015114 0ustar dereknderekn! Generated automatically by mantohlp 1 pdfdetach pdfdetach - Portable Document Format (PDF) document embedded file pdfdetach [options] [PDF-file] Pdfdetach lists or extracts embedded files (attachments) from a Porta- ble Document Format (PDF) file. () 2 ONFIGURATION_FIL Pdfdetach reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Some of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -list List all of the embedded files in the PDF file. File names are converted to the text encoding specified by the "-enc" switch. -save number Save the specified embedded file. By default, this uses the file name associated with the embedded file (as printed by the "-list" switch); the file name can be changed with the "-o" switch. -saveall Save all of the embedded files. This uses the file names asso- ciated with the embedded files (as printed by the "-list" switch). By default, the files are saved in the current direc- tory; this can be changed with the "-o" switch. -o path Set the file name used when saving an embedded file with the "-save" switch, or the directory used by "-saveall". -enc encoding-name Sets the encoding to use for text output (embedded file names). The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [config file: textEncoding] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/pdftops.hlp0000644000076400007640000002120111622305345014640 0ustar dereknderekn! Generated automatically by mantohlp 1 pdftops pdftops - Portable Document Format (PDF) to PostScript converter pdftops [options] [PDF-file [PS-file]] Pdftops converts Portable Document Format (PDF) files to PostScript so they can be printed. Pdftops reads the PDF file, PDF-file, and writes a PostScript file, PS- file. If PS-file is not specified, pdftops converts file.pdf to file.ps (or file.eps with the -eps option). If PS-file is '-', the PostScript is sent to stdout. () 2 ONFIGURATION_FIL Pdftops reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftops is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to print. -l number Specifies the last page to print. -level1 Generate Level 1 PostScript. The resulting PostScript files will be significantly larger (if they contain images), but will print on Level 1 printers. This also converts all images to black and white. No more than one of the PostScript level options (-level1, -level1sep, -level2, -level2sep, -level3, -level3Sep) may be given. [config file: psLevel] -level1sep Generate Level 1 separable PostScript. All colors are converted to CMYK. Images are written with separate stream data for the four components. [config file: psLevel] -level2 Generate Level 2 PostScript. Level 2 supports color images and image compression. This is the default setting. [config file: psLevel] -level2sep Generate Level 2 separable PostScript. All colors are converted to CMYK. The PostScript separation convention operators are used to handle custom (spot) colors. [config file: psLevel] -level3 Generate Level 3 PostScript. This enables all Level 2 features plus CID font embedding and masked image generation. [config file: psLevel] -level3Sep Generate Level 3 separable PostScript. The separation handling is the same as for -level2Sep. [config file: psLevel] -eps Generate an Encapsulated PostScript (EPS) file. An EPS file contains a single image, so if you use this option with a multi- page PDF file, you must use -f and -l to specify a single page. No more than one of the mode options (-eps, -form) may be given. -form Generate a PostScript form which can be imported by software that understands forms. A form contains a single page, so if you use this option with a multi-page PDF file, you must use -f and -l to specify a single page. The -level1 option cannot be used with -form. -opi Generate OPI comments for all images and forms which have OPI information. (This option is only available if pdftops was com- piled with OPI support.) [config file: psOPI] -noembt1 By default, any Type 1 fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make Post- Script files larger, but may be necessary for readable output. [config file: psEmbedType1Fonts] -noembtt By default, any TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option causes pdftops to substitute base fonts instead. Embedded fonts make PostScript files larger, but may be necessary for readable out- put. Also, some PostScript interpreters do not have TrueType rasterizers. [config file: psEmbedTrueTypeFonts] -noembcidps By default, any CID PostScript fonts which are embedded in the PDF file are copied into the PostScript file. This option dis- ables that embedding. No attempt is made to substitute for non- embedded CID PostScript fonts. [config file: psEmbedCID- PostScriptFonts] -noembcidtt By default, any CID TrueType fonts which are embedded in the PDF file are copied into the PostScript file. This option disables that embedding. No attempt is made to substitute for non-embed- ded CID TrueType fonts. [config file: psEmbedCIDTrueTypeFonts] -preload Convert PDF forms to PS procedures, and preload image data. This uses more memory in the PostScript interpreter, but gener- ates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. -paper size Set the paper size to one of "letter", "legal", "A4", or "A3". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. [config file: psPaperSize] -paperw size Set the paper width, in points. [config file: psPaperSize] -paperh size Set the paper height, in points. [config file: psPaperSize] -nocrop By default, output is cropped to the CropBox specified in the PDF file. This option disables cropping. [config file: psCrop] -expand Expand PDF pages smaller than the paper to fill the paper. By default, these pages are not scaled. [config file: psExpandS- maller] -noshrink Don't scale PDF pages which are larger than the paper. By default, pages larger than the paper are shrunk to fit. [config file: psShrinkLarger] -nocenter By default, PDF pages smaller than the paper (after any scaling) are centered on the paper. This option causes them to be aligned to the lower-left corner of the paper instead. [config file: psCenter] -pagecrop Treat the CropBox as the PDF page size. By default, the Media- Box is used as the page size. -duplex Set the Duplex pagedevice entry in the PostScript file. This tells duplex-capable printers to enable duplexing. [config file: psDuplex] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdftops software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/xpdfrc.50000644000076400007640000005737111622305345014051 0ustar dereknderekn.\" Copyright 2002-2011 Glyph & Cog, LLC .TH xpdfrc 5 "15 August 2011" .SH NAME xpdfrc \- configuration file for Xpdf tools (version 3.03) .SH DESCRIPTION All of the Xpdf tools read a single configuration file. If you have a .I .xpdfrc file in your home directory, it will be read. Otherwise, a system-wide configuration file will be read from .IR /usr/local/etc/xpdfrc , if it exists. (This is its default location; depending on build options, it may be placed elsewhere.) On Win32 systems, the .I xpdfrc file should be placed in the same directory as the executables. .PP The xpdfrc file consists of a series of configuration options, one per line. Blank lines and lines starting with a \'#' (comments) are ignored. .PP The following sections list all of the configuration options, sorted into functional groups. There is an examples section at the end. .SH INCLUDE FILES .TP .BI include " config\-file" Includes the specified config file. The effect of this is equivalent to inserting the contents of .I config\-file directly into the parent config file in place of the .I include command. Config files can be nested arbitrarily deeply. .SH CHARACTER MAPPING .TP .BI nameToUnicode " map\-file" Specifies a file with the mapping from character names to Unicode. This is used to handle PDF fonts that have valid encodings but no ToUnicode entry. Each line of a nameToUnicode file looks like this: .I " " hex\-string name The .I hex\-string is the Unicode (UCS-2) character index, and .I name is the corresponding character name. Multiple nameToUnicode files can be used; if a character name is given more than once, the code in the last specified file is used. There is a built-in default nameToUnicode table with all of Adobe's standard character names. .TP .BI cidToUnicode " registry\-ordering map\-file" Specifies the file with the mapping from character collection to Unicode. Each line of a cidToUnicode file represents one character: .I " " hex\-string The .I hex\-string is the Unicode (UCS-2) index for that character. The first line maps CID 0, the second line CID 1, etc. File size is determined by size of the character collection. Only one file is allowed per character collection; the last specified file is used. There are no built-in cidToUnicode mappings. .TP .BI unicodeToUnicode " font\-name\-substring map\-file" This is used to work around PDF fonts which have incorrect Unicode information. It specifies a file which maps from the given (incorrect) Unicode indexes to the correct ones. The mapping will be used for any font whose name contains .IR font\-name\-substring . Each line of a unicodeToUnicode file represents one Unicode character: .RI " " in\-hex " " out\-hex1 " " out\-hex2 " ..." The .I in\-hex field is an input (incorrect) Unicode index, and the rest of the fields are one or more output (correct) Unicode indexes. Each occurrence of .I in\-hex will be converted to the specified output sequence. .TP .BI unicodeMap " encoding\-name map\-file" Specifies the file with mapping from Unicode to .IR encoding\-name . These encodings are used for text output (see below). Each line of a unicodeMap file represents a range of one or more Unicode characters which maps linearly to a range in the output encoding: .nf .I " " in\-start\-hex in\-end\-hex out\-start\-hex .fi Entries for single characters can be abbreviated to: .nf .I " " in\-hex out\-hex .fi The .I in\-start\-hex and .I in\-end\-hex fields (or the single .I in\-hex field) specify the Unicode range. The .I out\-start\-hex field (or the .I out\-hex field) specifies the start of the output encoding range. The length of the .I out\-start\-hex (or .IR out\-hex ) string determines the length of the output characters (e.g., UTF-8 uses different numbers of bytes to represent characters in different ranges). Entries must be given in increasing Unicode order. Only one file is allowed per encoding; the last specified file is used. The .IR Latin1 , .IR ASCII7 , .IR Symbol , .IR ZapfDingbats , .IR UTF-8 , and .I UCS-2 encodings are predefined. .TP .BI cMapDir " registry\-ordering dir" Specifies a search directory, .IR dir , for CMaps for the .I registry\-ordering character collection. There can be multiple directories for a particular collection. There are no default CMap directories. .TP .BI toUnicodeDir " dir" Specifies a search directory, .IR dir , for ToUnicode CMaps. There can be multiple ToUnicode directories. There are no default ToUnicode directories. .SH GENERAL FONT CONFIGURATION .TP .BI fontFile " PDF\-font\-name font\-file" Maps a PDF font, .IR PDF\-font\-name , to a font for display or PostScript output. The font file, .IR font\-file , can be any type allowed in a PDF file. This command can be used for 8-bit or 16-bit (CID) fonts. .TP .BI fontDir " dir" Specifies a search directory for font files. There can be multiple fontDir commands; all of the specified directories will be searched in order. The font files can be Type 1 (.pfa or .pfb) or TrueType (.ttf or .ttc); other files in the directory will be ignored. The font file name (not including the extension) must exactly match the PDF font name. This search is performed if the font name doesn't match any of the fonts declared with the fontFile command. There are no default fontDir directories. .TP .BI fontFileCC " registry\-ordering font\-file" Maps the .I registry\-ordering character collection to a font for display or PostScript output. This mapping is used if the font name doesn't match any of the fonts declared with the fontFile, fontDir, psResidentFont16, or psResidentFontCC commands. .SH POSTSCRIPT FONT CONFIGURATION .TP .BR psFontPassthrough " yes | no" If set to "yes", pass 8-bit font names through to the PostScript output without substitution. Fonts which are not embedded in the PDF file are expected to be available on the printer. This defaults to "no". .TP .BI psResidentFont " PDF\-font\-name PS\-font\-name" When the 8-bit font .I PDF\-font\-name is used (without embedding) in a PDF file, it will be translated to the PostScript font .IR PS\-font\-name , which is assumed to be resident in the printer. Typically, .I PDF\-font\-name and .I PS\-font\-name are the same. By default, only the Base-14 fonts are assumed to be resident. .TP .BI psResidentFont16 " PDF\-font\-name wMode PS\-font\-name encoding" When the 16-bit (CID) font .I PDF\-font\-name with writing mode .I wMode is used (without embedding) in a PDF file, it will be translated to the PostScript font .IR PS\-font\-name , which is assumbed to be resident in the printer. The writing mode must be either \'H' for horizontal or \'V' for vertical. The resident font is assumed to use the specified encoding (which must have been defined with the unicodeMap command). .TP .BI psResidentFontCC " registry\-ordering wMode PS\-font\-name encoding" When a 16-bit (CID) font using the .I registry\-ordering character collection and .I wMode writing mode is used (without embedding) in a PDF file, the PostScript font, .IR PS\-font\-name , is substituted for it. The substituted font is assumbed to be resident in the printer. The writing mode must be either \'H' for horizontal or \'V' for vertical. The resident font is assumed to use the specified encoding (which must have been defined with the unicodeMap command). .TP .BR psEmbedType1Fonts " yes | no" If set to "no", prevents embedding of Type 1 fonts in generated PostScript. This defaults to "yes". .TP .BR psEmbedTrueTypeFonts " yes | no" If set to "no", prevents embedding of TrueType fonts in generated PostScript. This defaults to "yes". .TP .BR psEmbedCIDTrueTypeFonts " yes | no" If set to "no", prevents embedding of CID TrueType fonts in generated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". .TP .BR psEmbedCIDPostScriptFonts " yes | no" If set to "no", prevents embedding of CID PostScript fonts in generated PostScript. For Level 3 PostScript, this generates a CID font, for lower levels it generates a non-CID composite font. This defaults to "yes". .SH POSTSCRIPT CONTROL .TP .BI psPaperSize " width(pts) height(pts)" Sets the paper size for PostScript output. The .I width and .I height parameters give the paper size in PostScript points (1 point = 1/72 inch). .TP .BR psPaperSize " letter | legal | A4 | A3 | match" Sets the paper size for PostScript output to a standard size. The default paper size is set when xpdf and pdftops are built, typically to "letter" or "A4". This can also be set to "match", which will set the paper size to match the size specified in the PDF file. .TP .BR psImageableArea " llx lly urx ury" Sets the imageable area for PostScript output. The four integers are the coordinates of the lower-left and upper-right corners of the imageable region, specified in points (with the origin being the lower-left corner of the paper). This defaults to the full paper size; the psPaperSize option will reset the imageable area coordinates. .TP .BR psCrop " yes | no" If set to "yes", PostScript output is cropped to the CropBox specified in the PDF file; otherwise no cropping is done. This defaults to "yes". .TP .BR psExpandSmaller " yes | no" If set to "yes", PDF pages smaller than the PostScript imageable area are expanded to fill the imageable area. Otherwise, no scalling is done on smaller pages. This defaults to "no". .TP .BR psShrinkLarger " yes | no" If set to yes, PDF pages larger than the PostScript imageable area are shrunk to fit the imageable area. Otherwise, no scaling is done on larger pages. This defaults to "yes". .TP .BR psCenter " yes | no" If set to yes, PDF pages smaller than the PostScript imageable area (after any scaling) are centered in the imageable area. Otherwise, they are aligned at the lower-left corner of the imageable area. This defaults to "yes". .TP .BR psDuplex " yes | no" If set to "yes", the generated PostScript will set the "Duplex" pagedevice entry. This tells duplex-capable printers to enable duplexing. This defaults to "no". .TP .BR psLevel " level1 | level1sep | level2 | level2sep | level3 | level3Sep" Sets the PostScript level to generate. This defaults to "level2". .TP .BR psPreload " yes | no" If set to "yes", PDF forms are converted to PS procedures, and image data is preloaded. This uses more memory in the PostScript interpreter, but generates significantly smaller PS files in situations where, e.g., the same image is drawn on every page of a long document. This defaults to "no". .TP .BR psOPI " yes | no" If set to "yes", generates PostScript OPI comments for all images and forms which have OPI information. This option is only available if the Xpdf tools were compiled with OPI support. This defaults to "no". .TP .BR psASCIIHex " yes | no" If set to "yes", the ASCIIHexEncode filter will be used instead of ASCII85Encode for binary data. This defaults to "no". .TP .BR psUncompressPreloadedImages " yes | no" If set to "yes", all preloaded images in PS files will uncompressed. If set to "no", the original compressed images will be used when possible. The "yes" setting is useful to work around certain buggy PostScript interpreters. This defaults to "no". .TP .BR psRasterResolution " float" Set the resolution (in dpi) for rasterized pages in PostScript output. (Pdftops will rasterize pages which use transparency.) This defaults to 300. .TP .BR psRasterMono " yes | no" If set to "yes", rasterized pages in PS files will be monochrome (8-bit gray) instead of color. This defaults to "no". .TP .BR psAlwaysRasterize " yes | no" If set to "yes", all PostScript output will be rasterized. This defaults to "no". .TP .BI psFile " file\-or\-command" Sets the default PostScript file or print command for xpdf. Commands start with a \'|' character; anything else is a file. If the file name or command contains spaces it must be quoted. This defaults to unset, which tells xpdf to generate a name of the form .ps for a PDF file .pdf. .TP .BI fontDir " dir" See the description above, in the DISPLAY FONTS section. .SH TEXT CONTROL .TP .BI textEncoding " encoding\-name" Sets the encoding to use for text output. (This can be overridden with the "\-enc" switch on the command line.) The .I encoding\-name must be defined with the unicodeMap command (see above). This defaults to "Latin1". .TP .BR textEOL " unix | dos | mac" Sets the end-of-line convention to use for text output. The options are: .nf unix = LF dos = CR+LF mac = CR .fi (This can be overridden with the "\-eol" switch on the command line.) The default value is based on the OS where xpdf and pdftotext were built. .TP .BR textPageBreaks " yes | no" If set to "yes", text extraction will insert page breaks (form feed characters) between pages. This defaults to "yes". .TP .BR textKeepTinyChars " yes | no" If set to "yes", text extraction will keep all characters. If set to "no", text extraction will discard tiny (smaller than 3 point) characters after the first 50000 per page, avoiding extremely slow run times for PDF files that use special fonts to do shading or cross-hatching. This defaults to "no". .SH MISCELLANEOUS SETTINGS .TP .BR initialZoom " \fIpercentage\fR | page | width" Sets the initial zoom factor. A number specifies a zoom percentage, where 100 means 72 dpi. You may also specify \'page', to fit the page to the window size, or \'width', to fit the page width to the window width. .TP .BR continuousView " yes | no" If set to "yes", xpdf will start in continuous view mode, i.e., with one vertical screoll bar for the whole document. This defaults to "no". .TP .BR enableT1lib " yes | no" Enables or disables use of t1lib (a Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with t1lib support. ("enableT1lib" replaces the old "t1libControl" option.) This option defaults to "yes". .TP .BR enableFreeType " yes | no" Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". .TP .BR enableFreeType " yes | no" Enables or disables use of FreeType (a TrueType / Type 1 font rasterizer). This is only relevant if the Xpdf tools were built with FreeType support. ("enableFreeType" replaces the old "freetypeControl" option.) This option defaults to "yes". .TP .BR disableFreeTypeHinting " yes | no" If this is set to "yes", FreeType hinting will be forced off. This option defaults to "no". .TP .BR antialias " yes | no" Enables or disables font anti-aliasing in the PDF rasterizer. This option affects all font rasterizers. ("antialias" replaces the anti-aliasing control provided by the old "t1libControl" and "freetypeControl" options.) This default to "yes". .TP .BR vectorAntialias " yes | no" Enables or disables anti-aliasing of vector graphics in the PDF rasterizer. This defaults to "yes". .TP .BR antialiasPrinting " yes | no" If this is "yes", bitmaps sent to the printer will be antialiased (according to the "antialias" and "vectorAntialias" settings). If this is "no", printed bitmaps will not be antialiased. This defaults to "no". .TP .BR strokeAdjust " yes | no" Enables or disables stroke adjustment. Stroke adjustment moves horizontal and vertical lines by up to half a pixel to make them look "cleaner" when vector anti-aliasing is enabled. This defaults to "yes". .TP .BR screenType " dispersed | clustered | stochasticClustered" Sets the halftone screen type, which will be used when generating a monochrome (1-bit) bitmap. The three options are dispersed-dot dithering, clustered-dot dithering (with a round dot and 45-degree screen angle), and stochastic clustered-dot dithering. By default, "stochasticClustered" is used for resolutions of 300 dpi and higher, and "dispersed" is used for resolutions lower then 300 dpi. .TP .BI screenSize " integer" Sets the size of the (square) halftone screen threshold matrix. By default, this is 4 for dispersed-dot dithering, 10 for clustered-dot dithering, and 100 for stochastic clustered-dot dithering. .TP .BI screenDotRadius " integer" Sets the halftone screen dot radius. This is only used when screenType is set to stochasticClustered, and it defaults to 2. In clustered-dot mode, the dot radius is half of the screen size. Dispersed-dot dithering doesn't have a dot radius. .TP .BI screenGamma " float" Sets the halftone screen gamma correction parameter. Gamma values greater than 1 make the output brighter; gamma values less than 1 make it darker. The default value is 1. .TP .BI screenBlackThreshold " float" When halftoning, all values below this threshold are forced to solid black. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 0. .TP .BI screenWhiteThreshold " float" When halftoning, all values above this threshold are forced to solid white. This parameter is a floating point value between 0 (black) and 1 (white). The default value is 1. .TP .BI minLineWidth " float" Set the minimum line width, in device pixels. This affects the rasterizer only, not the PostScript converter (except when it uses rasterization to handle transparency). The default value is 0 (no minimum). .TP .BI drawAnnotations " yes | no" If set to "no", annotations will not be drawn or printed. The default value is "yes". .TP .BI overprintPreview " yes | no" If set to "yes", generate overprint preview output, honoring the OP/op/OPM settings in the PDF file. Ignored for non-CMYK output. The default value is "no". .TP .BI launchCommand " command" Sets the command executed when you click on a "launch"-type link. The intent is for the command to be a program/script which determines the file type and runs the appropriate viewer. The command line will consist of the file to be launched, followed by any parameters specified with the link. Do not use "%s" in "command". By default, this is unset, and Xpdf will simply try to execute the file (after prompting the user). .TP .BI urlCommand " command" Sets the command executed when you click on a URL link. The string "%s" will be replaced with the URL. (See the example below.) This has no default value. .TP .BI movieCommand " command" Sets the command executed when you click on a movie annotation. The string "%s" will be replaced with the movie file name. This has no default value. .TP .BI mapNumericCharNames " yes | no" If set to "yes", the Xpdf tools will attempt to map various numeric character names sometimes used in font subsets. In some cases this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "yes". .TP .BI mapUnknownCharNames " yes | no" If set to "yes", and mapNumericCharNames is set to "no", the Xpdf tools will apply a simple pass-through mapping (Unicode index = character code) for all unrecognized glyph names. (For CID fonts, setting mapNumericCharNames to "no" is unnecessary.) In some cases, this leads to usable text, and in other cases it leads to gibberish -- there is no way for Xpdf to tell. This defaults to "no". .TP .BI bind " modifiers-key context command ..." Add a key or mouse button binding. .I Modifiers can be zero or more of: .nf shift- ctrl- alt- .fi .I Key can be a regular ASCII character, or any one of: .nf space tab return enter backspace insert delete home end pgup pgdn left / right / up / down (arrow keys) f1 .. f35 (function keys) mousePress1 .. mousePress7 (mouse buttons) mouseRelease1 .. mouseRelease7 (mouse buttons) .fi .I Context is either "any" or a comma-separated combination of: .nf fullScreen / window (full screen mode on/off) continuous / singlePage (continuous mode on/off) overLink / offLink (mouse over link or not) scrLockOn / scrLockOff (scroll lock on/off) .fi The context string can include only one of each pair in the above list. .I Command is an Xpdf command (see the COMMANDS section of the .BR xpdf (1) man page for details). Multiple commands are separated by whitespace. The bind command replaces any existing binding, but only if it was defined for the exact same modifiers, key, and context. All tokens (modifiers, key, context, commands) are case-sensitive. Example key bindings: .nf # bind ctrl-a in any context to the nextPage # command bind ctrl-a any nextPage # bind uppercase B, when in continuous mode # with scroll lock on, to the reload command # followed by the prevPage command bind B continuous,scrLockOn reload prevPage .fi See the .BR xpdf (1) man page for more examples. .TP .BI unbind " modifiers-key context" Removes a key binding established with the bind command. This is most useful to remove default key bindings before establishing new ones (e.g., if the default key binding is given for "any" context, and you want to create new key bindings for multiple contexts). .TP .BI printCommands " yes | no" If set to "yes", drawing commands are printed as they're executed (useful for debugging). This defaults to "no". .TP .BI errQuiet " yes | no" If set to "yes", this suppresses all error and warning messages from all of the Xpdf tools. This defaults to "no". .SH EXAMPLES The following is a sample xpdfrc file. .nf # from the Thai support package nameToUnicode /usr/local/share/xpdf/Thai.nameToUnicode # from the Japanese support package cidToUnicode Adobe-Japan1 /usr/local/share/xpdf/Adobe-Japan1.cidToUnicode unicodeMap JISX0208 /usr/local/share/xpdf/JISX0208.unicodeMap cMapDir Adobe-Japan1 /usr/local/share/xpdf/cmap/Adobe-Japan1 # use the Base-14 Type 1 fonts from ghostscript fontFile Times-Roman /usr/local/share/ghostscript/fonts/n021003l.pfb fontFile Times-Italic /usr/local/share/ghostscript/fonts/n021023l.pfb fontFile Times-Bold /usr/local/share/ghostscript/fonts/n021004l.pfb fontFile Times-BoldItalic /usr/local/share/ghostscript/fonts/n021024l.pfb fontFile Helvetica /usr/local/share/ghostscript/fonts/n019003l.pfb fontFile Helvetica-Oblique /usr/local/share/ghostscript/fonts/n019023l.pfb fontFile Helvetica-Bold /usr/local/share/ghostscript/fonts/n019004l.pfb fontFile Helvetica-BoldOblique /usr/local/share/ghostscript/fonts/n019024l.pfb fontFile Courier /usr/local/share/ghostscript/fonts/n022003l.pfb fontFile Courier-Oblique /usr/local/share/ghostscript/fonts/n022023l.pfb fontFile Courier-Bold /usr/local/share/ghostscript/fonts/n022004l.pfb fontFile Courier-BoldOblique /usr/local/share/ghostscript/fonts/n022024l.pfb fontFile Symbol /usr/local/share/ghostscript/fonts/s050000l.pfb fontFile ZapfDingbats /usr/local/share/ghostscript/fonts/d050000l.pfb # use the Bakoma Type 1 fonts # (this assumes they happen to be installed in /usr/local/fonts/bakoma) fontDir /usr/local/fonts/bakoma # set some PostScript options psPaperSize letter psDuplex no psLevel level2 psEmbedType1Fonts yes psEmbedTrueTypeFonts yes psFile "| lpr \-Pprinter5" # assume that the PostScript printer has the Univers and # Univers-Bold fonts psResidentFont Univers Univers psResidentFont Univers-Bold Univers-Bold # set the text output options textEncoding UTF-8 textEOL unix # misc options enableT1lib yes enableFreeType yes launchCommand viewer-script urlCommand "netscape \-remote 'openURL(%s)'" .fi .SH FILES .TP .B /usr/local/etc/xpdfrc This is the default location for the system-wide configuration file. Depending on build options, it may be placed elsewhere. .TP .B $HOME/.xpdfrc This is the user's configuration file. If it exists, it will be read in place of the system-wide file. .SH AUTHOR The Xpdf software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdfinfo.cat0000644000076400007640000000735511622305345014610 0ustar derekndereknpdfinfo(1) pdfinfo(1) NAME pdfinfo - Portable Document Format (PDF) document information extractor (version 3.03) SYNOPSIS pdfinfo [options] [PDF-file] DESCRIPTION Pdfinfo prints the contents of the 'Info' dictionary (plus some other useful information) from a Portable Document Format (PDF) file. The 'Info' dictionary contains the following values: title subject keywords author creator producer creation date modification date In addition, the following information is printed: tagged (yes/no) form (AcroForm / XFA / none) page count encrypted flag (yes/no) print and copy permissions (if encrypted) page size file size linearized (yes/no) PDF version metadata (only if requested) CONFIGURATION FILE Pdfinfo reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to examine. If multiple pages are requested using the "-f" and "-l" options, the size of each requested page (and, optionally, the bounding boxes for each requested page) are printed. Otherwise, only page one is exam- ined. -l number Specifies the last page to examine. -box Prints the page box bounding boxes: MediaBox, CropBox, BleedBox, TrimBox, and ArtBox. -meta Prints document-level metadata. (This is the "Metadata" stream from the PDF file's Catalog object.) -rawdates Prints the raw (undecoded) date strings, directly from the PDF file. -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [con- fig file: textEncoding] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdfinfo(1) xpdf-3.03/doc/pdffonts.cat0000644000076400007640000000653111622305345015001 0ustar derekndereknpdffonts(1) pdffonts(1) NAME pdffonts - Portable Document Format (PDF) font analyzer (version 3.03) SYNOPSIS pdffonts [options] [PDF-file] DESCRIPTION Pdffonts lists the fonts used in a Portable Document Format (PDF) file along with various information for each font. The following information is listed for each font: name the font name, exactly as given in the PDF file (potentially including a subset prefix) type the font type -- see below for details emb "yes" if the font is embedded in the PDF file sub "yes" if the font is a subset uni "yes" if there is an explicit "ToUnicode" map in the PDF file (the absence of a ToUnicode map doesn't necessarily mean that the text can't be converted to Unicode) object ID the font dictionary object ID (number and generation) PDF files can contain the following types of fonts: Type 1 Type 1C -- aka Compact Font Format (CFF) Type 1C (OT) -- OpenType with 8-bit CFF data Type 3 TrueType TrueType (OT) -- OpenType with 8-bit TrueType data CID Type 0 -- 16-bit font with no specified type CID Type 0C -- 16-bit PostScript CFF font CID Type 0C (OT) -- OpenType with CID CFF data CID TrueType -- 16-bit TrueType font CID TrueType (OT) -- OpenType with CID TrueType data CONFIGURATION FILE Pdffonts reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdffonts is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to analyze. -l number Specifies the last page to analyze. -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdffonts software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdffonts(1) xpdf-3.03/doc/pdfimages.hlp0000644000076400007640000000627211622305345015133 0ustar dereknderekn! Generated automatically by mantohlp 1 pdfimages pdfimages - Portable Document Format (PDF) image extractor pdfimages [options] PDF-file image-root Pdfimages saves images from a Portable Document Format (PDF) file as Portable Pixmap (PPM), Portable Bitmap (PBM), or JPEG files. Pdfimages reads the PDF file, scans one or more pages, PDF-file, and writes one PPM, PBM, or JPEG file for each image, image-root-nnn.xxx, where nnn is the image number and xxx is the image type (.ppm, .pbm, .jpg). NB: pdfimages extracts the raw image data from the PDF file, without performing any additional transforms. Any rotation, clipping, color inversion, etc. done by the PDF content stream is ignored. () 2 ONFIGURATION_FIL Pdfimages reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfimages is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to scan. -l number Specifies the last page to scan. -j Normally, all images are written as PBM (for monochrome images) or PPM (for non-monochrome images) files. With this option, images in DCT format are saved as JPEG files. All non-DCT images are saved in PBM/PPM format as usual. -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdfimages software and documentation are copyright 1998-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdftoppm(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/pdfimages.10000644000076400007640000000502411622305345014502 0ustar dereknderekn.\" Copyright 1998-2011 Glyph & Cog, LLC .TH pdfimages 1 "15 August 2011" .SH NAME pdfimages \- Portable Document Format (PDF) image extractor (version 3.03) .SH SYNOPSIS .B pdfimages [options] .I PDF-file image-root .SH DESCRIPTION .B Pdfimages saves images from a Portable Document Format (PDF) file as Portable Pixmap (PPM), Portable Bitmap (PBM), or JPEG files. .PP Pdfimages reads the PDF file, scans one or more pages, .IR PDF-file , and writes one PPM, PBM, or JPEG file for each image, .IR image-root - nnn . xxx , where .I nnn is the image number and .I xxx is the image type (.ppm, .pbm, .jpg). .PP NB: pdfimages extracts the raw image data from the PDF file, without performing any additional transforms. Any rotation, clipping, color inversion, etc. done by the PDF content stream is ignored. .SH CONFIGURATION FILE Pdfimages reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfimages is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to scan. .TP .BI \-l " number" Specifies the last page to scan. .TP .B \-j Normally, all images are written as PBM (for monochrome images) or PPM (for non-monochrome images) files. With this option, images in DCT format are saved as JPEG files. All non-DCT images are saved in PBM/PPM format as usual. .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .B \-q Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdfimages software and documentation are copyright 1998-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdftoppm.10000644000076400007640000000577011622305345014404 0ustar dereknderekn.\" Copyright 2005-2011 Glyph & Cog, LLC .TH pdftoppm 1 "15 August 2011" .SH NAME pdftoppm \- Portable Document Format (PDF) to Portable Pixmap (PPM) converter (version 3.03) .SH SYNOPSIS .B pdftoppm [options] .I PDF-file PPM-root .SH DESCRIPTION .B Pdftoppm converts Portable Document Format (PDF) files to color image files in Portable Pixmap (PPM) format, grayscale image files in Portable Graymap (PGM) format, or monochrome image files in Portable Bitmap (PBM) format. .PP Pdftoppm reads the PDF file, .IR PDF-file , and writes one PPM file for each page, .IR PPM-root - nnnnnn .ppm, where .I nnnnnn is the page number. If .I PPM-root is \'-', the image is sent to stdout (this is probably only useful when converting a single page). .SH CONFIGURATION FILE Pdftoppm reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftoppm is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to convert. .TP .BI \-l " number" Specifies the last page to convert. .TP .BI \-r " number" Specifies the resolution, in DPI. The default is 150 DPI. .TP .B \-mono Generate a monochrome PBM file (instead of a color PPM file). .TP .B \-gray Generate a grayscale PGM file (instead of a color PPM file). .TP .BI \-t1lib " yes | no" Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". .RB "[config file: " enableT1lib ] .TP .BI \-freetype " yes | no" Enable or disable FreeType (a TrueType / Type 1 font rasterizer). This defaults to "yes". .RB "[config file: " enableFreeType ] .TP .BI \-aa " yes | no" Enable or disable font anti-aliasing. This defaults to "yes". .RB "[config file: " antialias ] .TP .BI \-aaVector " yes | no" Enable or disable vector anti-aliasing. This defaults to "yes". .RB "[config file: " vectorAntialias ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .B \-q Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdftoppm software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdftotext (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdftotext.10000644000076400007640000000672411622305345014574 0ustar dereknderekn.\" Copyright 1997-2011 Glyph & Cog, LLC .TH pdftotext 1 "15 August 2011" .SH NAME pdftotext \- Portable Document Format (PDF) to text converter (version 3.03) .SH SYNOPSIS .B pdftotext [options] .RI [ PDF-file .RI [ text-file ]] .SH DESCRIPTION .B Pdftotext converts Portable Document Format (PDF) files to plain text. .PP Pdftotext reads the PDF file, .IR PDF-file , and writes a text file, .IR text-file . If .I text-file is not specified, pdftotext converts .I file.pdf to .IR file.txt . If .I text-file is \'-', the text is sent to stdout. .SH CONFIGURATION FILE Pdftotext reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftotext is built). See the .BR xpdfrc (5) man page for details. .SH OPTIONS Many of the following options can be set with configuration file commands. These are listed in square brackets with the description of the corresponding command line option. .TP .BI \-f " number" Specifies the first page to convert. .TP .BI \-l " number" Specifies the last page to convert. .TP .B \-layout Maintain (as best as possible) the original physical layout of the text. The default is to \'undo' physical layout (columns, hyphenation, etc.) and output the text in reading order. .TP .BI \-fixed " number" Assume fixed-pitch (or tabular) text, with the specified character width (in points). This forces physical layout mode. .TP .B \-raw Keep the text in content stream order. This is a hack which often "undoes" column formatting, etc. Use of raw mode is no longer recommended. .TP .B \-htmlmeta Generate a simple HTML file, including the meta information. This simply wraps the text in
 and 
and prepends the meta headers. .TP .BI \-enc " encoding-name" Sets the encoding to use for text output. The .I encoding\-name must be defined with the unicodeMap command (see .BR xpdfrc (5)). The encoding name is case-sensitive. This defaults to "Latin1" (which is a built-in encoding). .RB "[config file: " textEncoding ] .TP .BI \-eol " unix | dos | mac" Sets the end-of-line convention to use for text output. .RB "[config file: " textEOL ] .TP .B \-nopgbrk Don't insert page breaks (form feed characters) between pages. .RB "[config file: " textPageBreaks ] .TP .BI \-opw " password" Specify the owner password for the PDF file. Providing this will bypass all security restrictions. .TP .BI \-upw " password" Specify the user password for the PDF file. .TP .B \-q Don't print any messages or errors. .RB "[config file: " errQuiet ] .TP .BI \-cfg " config-file" Read .I config-file in place of ~/.xpdfrc or the system-wide config file. .TP .B \-v Print copyright and version information. .TP .B \-h Print usage information. .RB ( \-help and .B \-\-help are equivalent.) .SH BUGS Some PDF files contain fonts whose encodings have been mangled beyond recognition. There is no way (short of OCR) to extract text from these files. .SH EXIT CODES The Xpdf tools use the following exit codes: .TP 0 No error. .TP 1 Error opening a PDF file. .TP 2 Error opening an output file. .TP 3 Error related to PDF permissions. .TP 99 Other error. .SH AUTHOR The pdftotext software and documentation are copyright 1996-2011 Glyph & Cog, LLC. .SH "SEE ALSO" .BR xpdf (1), .BR pdftops (1), .BR pdfinfo (1), .BR pdffonts (1), .BR pdfdetach (1), .BR pdftoppm (1), .BR pdfimages (1), .BR xpdfrc (5) .br .B http://www.foolabs.com/xpdf/ xpdf-3.03/doc/pdfinfo.hlp0000644000076400007640000001005411622305345014612 0ustar dereknderekn! Generated automatically by mantohlp 1 pdfinfo pdfinfo - Portable Document Format (PDF) document information pdfinfo [options] [PDF-file] Pdfinfo prints the contents of the 'Info' dictionary (plus some other useful information) from a Portable Document Format (PDF) file. The 'Info' dictionary contains the following values: title subject keywords author creator producer creation date modification date In addition, the following information is printed: tagged (yes/no) form (AcroForm / XFA / none) page count encrypted flag (yes/no) print and copy permissions (if encrypted) page size file size linearized (yes/no) PDF version metadata (only if requested) () 2 ONFIGURATION_FIL Pdfinfo reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfinfo is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to examine. If multiple pages are requested using the "-f" and "-l" options, the size of each requested page (and, optionally, the bounding boxes for each requested page) are printed. Otherwise, only page one is exam- ined. -l number Specifies the last page to examine. -box Prints the page box bounding boxes: MediaBox, CropBox, BleedBox, TrimBox, and ArtBox. -meta Prints document-level metadata. (This is the "Metadata" stream from the PDF file's Catalog object.) -rawdates Prints the raw (undecoded) date strings, directly from the PDF file. -enc encoding-name Sets the encoding to use for text output. The encoding-name must be defined with the unicodeMap command (see xpdfrc(5)). This defaults to "Latin1" (which is a built-in encoding). [con- fig file: textEncoding] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -cfg config-file Read config-file in place of ~/.xpdfrc or the system-wide config file. -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdfinfo software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdffonts(1), pdfdetach(1), pdftoppm(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/doc/pdftoppm.cat0000644000076400007640000000656411622305345015015 0ustar derekndereknpdftoppm(1) pdftoppm(1) NAME pdftoppm - Portable Document Format (PDF) to Portable Pixmap (PPM) con- verter (version 3.03) SYNOPSIS pdftoppm [options] PDF-file PPM-root DESCRIPTION Pdftoppm converts Portable Document Format (PDF) files to color image files in Portable Pixmap (PPM) format, grayscale image files in Porta- ble Graymap (PGM) format, or monochrome image files in Portable Bitmap (PBM) format. Pdftoppm reads the PDF file, PDF-file, and writes one PPM file for each page, PPM-root-nnnnnn.ppm, where nnnnnn is the page number. If PPM- root is '-', the image is sent to stdout (this is probably only useful when converting a single page). CONFIGURATION FILE Pdftoppm reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftoppm is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to convert. -l number Specifies the last page to convert. -r number Specifies the resolution, in DPI. The default is 150 DPI. -mono Generate a monochrome PBM file (instead of a color PPM file). -gray Generate a grayscale PGM file (instead of a color PPM file). -t1lib yes | no Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". [config file: enableT1lib] -freetype yes | no Enable or disable FreeType (a TrueType / Type 1 font raster- izer). This defaults to "yes". [config file: enableFreeType] -aa yes | no Enable or disable font anti-aliasing. This defaults to "yes". [config file: antialias] -aaVector yes | no Enable or disable vector anti-aliasing. This defaults to "yes". [config file: vectorAntialias] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdftoppm software and documentation are copyright 1996-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdftoppm(1) xpdf-3.03/doc/pdfimages.cat0000644000076400007640000000556311622305345015121 0ustar derekndereknpdfimages(1) pdfimages(1) NAME pdfimages - Portable Document Format (PDF) image extractor (version 3.03) SYNOPSIS pdfimages [options] PDF-file image-root DESCRIPTION Pdfimages saves images from a Portable Document Format (PDF) file as Portable Pixmap (PPM), Portable Bitmap (PBM), or JPEG files. Pdfimages reads the PDF file, scans one or more pages, PDF-file, and writes one PPM, PBM, or JPEG file for each image, image-root-nnn.xxx, where nnn is the image number and xxx is the image type (.ppm, .pbm, .jpg). NB: pdfimages extracts the raw image data from the PDF file, without performing any additional transforms. Any rotation, clipping, color inversion, etc. done by the PDF content stream is ignored. CONFIGURATION FILE Pdfimages reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdfimages is built). See the xpdfrc(5) man page for details. OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to scan. -l number Specifies the last page to scan. -j Normally, all images are written as PBM (for monochrome images) or PPM (for non-monochrome images) files. With this option, images in DCT format are saved as JPEG files. All non-DCT images are saved in PBM/PPM format as usual. -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) EXIT CODES The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. AUTHOR The pdfimages software and documentation are copyright 1998-2011 Glyph & Cog, LLC. SEE ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdftoppm(1), xpdfrc(5) http://www.foolabs.com/xpdf/ 15 August 2011 pdfimages(1) xpdf-3.03/doc/pdftoppm.hlp0000644000076400007640000000726211622305345015025 0ustar dereknderekn! Generated automatically by mantohlp 1 pdftoppm pdftoppm - Portable Document Format (PDF) to Portable Pixmap (PPM) pdftoppm [options] PDF-file PPM-root Pdftoppm converts Portable Document Format (PDF) files to color image files in Portable Pixmap (PPM) format, grayscale image files in Porta- ble Graymap (PGM) format, or monochrome image files in Portable Bitmap (PBM) format. Pdftoppm reads the PDF file, PDF-file, and writes one PPM file for each page, PPM-root-nnnnnn.ppm, where nnnnnn is the page number. If PPM- root is '-', the image is sent to stdout (this is probably only useful when converting a single page). () 2 ONFIGURATION_FIL Pdftoppm reads a configuration file at startup. It first tries to find the user's private config file, ~/.xpdfrc. If that doesn't exist, it looks for a system-wide config file, typically /usr/local/etc/xpdfrc (but this location can be changed when pdftoppm is built). See the xpdfrc(5) man page for details. () 2 OPTIONS Many of the following options can be set with configuration file com- mands. These are listed in square brackets with the description of the corresponding command line option. -f number Specifies the first page to convert. -l number Specifies the last page to convert. -r number Specifies the resolution, in DPI. The default is 150 DPI. -mono Generate a monochrome PBM file (instead of a color PPM file). -gray Generate a grayscale PGM file (instead of a color PPM file). -t1lib yes | no Enable or disable t1lib (a Type 1 font rasterizer). This defaults to "yes". [config file: enableT1lib] -freetype yes | no Enable or disable FreeType (a TrueType / Type 1 font raster- izer). This defaults to "yes". [config file: enableFreeType] -aa yes | no Enable or disable font anti-aliasing. This defaults to "yes". [config file: antialias] -aaVector yes | no Enable or disable vector anti-aliasing. This defaults to "yes". [config file: vectorAntialias] -opw password Specify the owner password for the PDF file. Providing this will bypass all security restrictions. -upw password Specify the user password for the PDF file. -q Don't print any messages or errors. [config file: errQuiet] -v Print copyright and version information. -h Print usage information. (-help and --help are equivalent.) () 2 XIT_CODE The Xpdf tools use the following exit codes: 0 No error. 1 Error opening a PDF file. 2 Error opening an output file. 3 Error related to PDF permissions. 99 Other error. () 2 AUTHOR The pdftoppm software and documentation are copyright 1996-2011 Glyph & Cog, LLC. () 2 SEE_ALSO xpdf(1), pdftops(1), pdftotext(1), pdfinfo(1), pdffonts(1), pdfde- tach(1), pdfimages(1), xpdfrc(5) http://www.foolabs.com/xpdf/ () xpdf-3.03/goo/0000755000076400007640000000000011622305345012477 5ustar derekndereknxpdf-3.03/goo/gmem.h0000644000076400007640000000270611622305345013602 0ustar dereknderekn/* * gmem.h * * Memory routines with out-of-memory checking. * * Copyright 1996-2003 Glyph & Cog, LLC */ #ifndef GMEM_H #define GMEM_H #include #include #if USE_EXCEPTIONS class GMemException { public: GMemException() {} ~GMemException() {} }; #define GMEM_EXCEP throw(GMemException) #else // USE_EXCEPTIONS #define GMEM_EXCEP #endif // USE_EXCEPTIONS #ifdef __cplusplus extern "C" { #endif /* * Same as malloc, but prints error message and exits if malloc() * returns NULL. */ extern void *gmalloc(int size) GMEM_EXCEP; /* * Same as realloc, but prints error message and exits if realloc() * returns NULL. If

is NULL, calls malloc instead of realloc(). */ extern void *grealloc(void *p, int size) GMEM_EXCEP; /* * These are similar to gmalloc and grealloc, but take an object count * and size. The result is similar to allocating nObjs * objSize * bytes, but there is an additional error check that the total size * doesn't overflow an int. */ extern void *gmallocn(int nObjs, int objSize) GMEM_EXCEP; extern void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP; /* * Same as free, but checks for and ignores NULL pointers. */ extern void gfree(void *p); #ifdef DEBUG_MEM /* * Report on unfreed memory. */ extern void gMemReport(FILE *f); #else #define gMemReport(f) #endif /* * Allocate memory and copy a string into it. */ extern char *copyString(const char *s); #ifdef __cplusplus } #endif #endif xpdf-3.03/goo/GHash.cc0000644000076400007640000001404511622305345014004 0ustar dereknderekn//======================================================================== // // GHash.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "gmem.h" #include "GString.h" #include "GHash.h" //------------------------------------------------------------------------ struct GHashBucket { GString *key; union { void *p; int i; } val; GHashBucket *next; }; struct GHashIter { int h; GHashBucket *p; }; //------------------------------------------------------------------------ GHash::GHash(GBool deleteKeysA) { int h; deleteKeys = deleteKeysA; size = 7; tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } len = 0; } GHash::~GHash() { GHashBucket *p; int h; for (h = 0; h < size; ++h) { while (tab[h]) { p = tab[h]; tab[h] = p->next; if (deleteKeys) { delete p->key; } delete p; } } gfree(tab); } void GHash::add(GString *key, void *val) { GHashBucket *p; int h; // expand the table if necessary if (len >= size) { expand(); } // add the new symbol p = new GHashBucket; p->key = key; p->val.p = val; h = hash(key); p->next = tab[h]; tab[h] = p; ++len; } void GHash::add(GString *key, int val) { GHashBucket *p; int h; // expand the table if necessary if (len >= size) { expand(); } // add the new symbol p = new GHashBucket; p->key = key; p->val.i = val; h = hash(key); p->next = tab[h]; tab[h] = p; ++len; } void GHash::replace(GString *key, void *val) { GHashBucket *p; int h; if ((p = find(key, &h))) { p->val.p = val; if (deleteKeys) { delete key; } } else { add(key, val); } } void GHash::replace(GString *key, int val) { GHashBucket *p; int h; if ((p = find(key, &h))) { p->val.i = val; if (deleteKeys) { delete key; } } else { add(key, val); } } void *GHash::lookup(GString *key) { GHashBucket *p; int h; if (!(p = find(key, &h))) { return NULL; } return p->val.p; } int GHash::lookupInt(GString *key) { GHashBucket *p; int h; if (!(p = find(key, &h))) { return 0; } return p->val.i; } void *GHash::lookup(const char *key) { GHashBucket *p; int h; if (!(p = find(key, &h))) { return NULL; } return p->val.p; } int GHash::lookupInt(const char *key) { GHashBucket *p; int h; if (!(p = find(key, &h))) { return 0; } return p->val.i; } void *GHash::remove(GString *key) { GHashBucket *p; GHashBucket **q; void *val; int h; if (!(p = find(key, &h))) { return NULL; } q = &tab[h]; while (*q != p) { q = &((*q)->next); } *q = p->next; if (deleteKeys) { delete p->key; } val = p->val.p; delete p; --len; return val; } int GHash::removeInt(GString *key) { GHashBucket *p; GHashBucket **q; int val; int h; if (!(p = find(key, &h))) { return 0; } q = &tab[h]; while (*q != p) { q = &((*q)->next); } *q = p->next; if (deleteKeys) { delete p->key; } val = p->val.i; delete p; --len; return val; } void *GHash::remove(const char *key) { GHashBucket *p; GHashBucket **q; void *val; int h; if (!(p = find(key, &h))) { return NULL; } q = &tab[h]; while (*q != p) { q = &((*q)->next); } *q = p->next; if (deleteKeys) { delete p->key; } val = p->val.p; delete p; --len; return val; } int GHash::removeInt(const char *key) { GHashBucket *p; GHashBucket **q; int val; int h; if (!(p = find(key, &h))) { return 0; } q = &tab[h]; while (*q != p) { q = &((*q)->next); } *q = p->next; if (deleteKeys) { delete p->key; } val = p->val.i; delete p; --len; return val; } void GHash::startIter(GHashIter **iter) { *iter = new GHashIter; (*iter)->h = -1; (*iter)->p = NULL; } GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { if (!*iter) { return gFalse; } if ((*iter)->p) { (*iter)->p = (*iter)->p->next; } while (!(*iter)->p) { if (++(*iter)->h == size) { delete *iter; *iter = NULL; return gFalse; } (*iter)->p = tab[(*iter)->h]; } *key = (*iter)->p->key; *val = (*iter)->p->val.p; return gTrue; } GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { if (!*iter) { return gFalse; } if ((*iter)->p) { (*iter)->p = (*iter)->p->next; } while (!(*iter)->p) { if (++(*iter)->h == size) { delete *iter; *iter = NULL; return gFalse; } (*iter)->p = tab[(*iter)->h]; } *key = (*iter)->p->key; *val = (*iter)->p->val.i; return gTrue; } void GHash::killIter(GHashIter **iter) { delete *iter; *iter = NULL; } void GHash::expand() { GHashBucket **oldTab; GHashBucket *p; int oldSize, h, i; oldSize = size; oldTab = tab; size = 2*size + 1; tab = (GHashBucket **)gmallocn(size, sizeof(GHashBucket *)); for (h = 0; h < size; ++h) { tab[h] = NULL; } for (i = 0; i < oldSize; ++i) { while (oldTab[i]) { p = oldTab[i]; oldTab[i] = oldTab[i]->next; h = hash(p->key); p->next = tab[h]; tab[h] = p; } } gfree(oldTab); } GHashBucket *GHash::find(GString *key, int *h) { GHashBucket *p; *h = hash(key); for (p = tab[*h]; p; p = p->next) { if (!p->key->cmp(key)) { return p; } } return NULL; } GHashBucket *GHash::find(const char *key, int *h) { GHashBucket *p; *h = hash(key); for (p = tab[*h]; p; p = p->next) { if (!p->key->cmp(key)) { return p; } } return NULL; } int GHash::hash(GString *key) { const char *p; unsigned int h; int i; h = 0; for (p = key->getCString(), i = 0; i < key->getLength(); ++p, ++i) { h = 17 * h + (int)(*p & 0xff); } return (int)(h % size); } int GHash::hash(const char *key) { const char *p; unsigned int h; h = 0; for (p = key; *p; ++p) { h = 17 * h + (int)(*p & 0xff); } return (int)(h % size); } xpdf-3.03/goo/gmem.cc0000644000076400007640000001304611622305345013737 0ustar dereknderekn/* * gmem.c * * Memory routines with out-of-memory checking. * * Copyright 1996-2003 Glyph & Cog, LLC */ #include #include #include #include #include #include #include "gmem.h" #ifdef DEBUG_MEM typedef struct _GMemHdr { unsigned int magic; int size; int index; struct _GMemHdr *next, *prev; } GMemHdr; #define gMemHdrSize ((sizeof(GMemHdr) + 7) & ~7) #define gMemTrlSize (sizeof(long)) #define gMemMagic 0xabcd9999 #if gmemTrlSize==8 #define gMemDeadVal 0xdeadbeefdeadbeefUL #else #define gMemDeadVal 0xdeadbeefUL #endif /* round data size so trailer will be aligned */ #define gMemDataSize(size) \ ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize) static GMemHdr *gMemHead = NULL; static GMemHdr *gMemTail = NULL; static int gMemIndex = 0; static int gMemAlloc = 0; static int gMemInUse = 0; #endif /* DEBUG_MEM */ void *gmalloc(int size) GMEM_EXCEP { #ifdef DEBUG_MEM int size1; char *mem; GMemHdr *hdr; void *data; unsigned long *trl, *p; if (size < 0) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Invalid memory allocation size\n"); exit(1); #endif } if (size == 0) { return NULL; } size1 = gMemDataSize(size); if (!(mem = (char *)malloc(size1 + gMemHdrSize + gMemTrlSize))) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Out of memory\n"); exit(1); #endif } hdr = (GMemHdr *)mem; data = (void *)(mem + gMemHdrSize); trl = (unsigned long *)(mem + gMemHdrSize + size1); hdr->magic = gMemMagic; hdr->size = size; hdr->index = gMemIndex++; if (gMemTail) { gMemTail->next = hdr; hdr->prev = gMemTail; gMemTail = hdr; } else { hdr->prev = NULL; gMemHead = gMemTail = hdr; } hdr->next = NULL; ++gMemAlloc; gMemInUse += size; for (p = (unsigned long *)data; p <= trl; ++p) { *p = gMemDeadVal; } return data; #else void *p; if (size < 0) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Invalid memory allocation size\n"); exit(1); #endif } if (size == 0) { return NULL; } if (!(p = malloc(size))) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Out of memory\n"); exit(1); #endif } return p; #endif } void *grealloc(void *p, int size) GMEM_EXCEP { #ifdef DEBUG_MEM GMemHdr *hdr; void *q; int oldSize; if (size < 0) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Invalid memory allocation size\n"); exit(1); #endif } if (size == 0) { if (p) { gfree(p); } return NULL; } if (p) { hdr = (GMemHdr *)((char *)p - gMemHdrSize); oldSize = hdr->size; q = gmalloc(size); memcpy(q, p, size < oldSize ? size : oldSize); gfree(p); } else { q = gmalloc(size); } return q; #else void *q; if (size < 0) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Invalid memory allocation size\n"); exit(1); #endif } if (size == 0) { if (p) { free(p); } return NULL; } if (p) { q = realloc(p, size); } else { q = malloc(size); } if (!q) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Out of memory\n"); exit(1); #endif } return q; #endif } void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { int n; if (nObjs == 0) { return NULL; } n = nObjs * objSize; if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Bogus memory allocation size\n"); exit(1); #endif } return gmalloc(n); } void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { int n; if (nObjs == 0) { if (p) { gfree(p); } return NULL; } n = nObjs * objSize; if (objSize <= 0 || nObjs < 0 || nObjs >= INT_MAX / objSize) { #if USE_EXCEPTIONS throw GMemException(); #else fprintf(stderr, "Bogus memory allocation size\n"); exit(1); #endif } return grealloc(p, n); } void gfree(void *p) { #ifdef DEBUG_MEM int size; GMemHdr *hdr; unsigned long *trl, *clr; if (p) { hdr = (GMemHdr *)((char *)p - gMemHdrSize); if (hdr->magic == gMemMagic && ((hdr->prev == NULL) == (hdr == gMemHead)) && ((hdr->next == NULL) == (hdr == gMemTail))) { if (hdr->prev) { hdr->prev->next = hdr->next; } else { gMemHead = hdr->next; } if (hdr->next) { hdr->next->prev = hdr->prev; } else { gMemTail = hdr->prev; } --gMemAlloc; gMemInUse -= hdr->size; size = gMemDataSize(hdr->size); trl = (unsigned long *)((char *)hdr + gMemHdrSize + size); if (*trl != gMemDeadVal) { fprintf(stderr, "Overwrite past end of block %d at address %p\n", hdr->index, p); } for (clr = (unsigned long *)hdr; clr <= trl; ++clr) { *clr = gMemDeadVal; } free(hdr); } else { fprintf(stderr, "Attempted to free bad address %p\n", p); } } #else if (p) { free(p); } #endif } #ifdef DEBUG_MEM void gMemReport(FILE *f) { GMemHdr *p; fprintf(f, "%d memory allocations in all\n", gMemIndex); if (gMemAlloc > 0) { fprintf(f, "%d memory blocks left allocated:\n", gMemAlloc); fprintf(f, " index size\n"); fprintf(f, "-------- --------\n"); for (p = gMemHead; p; p = p->next) { fprintf(f, "%8d %8d\n", p->index, p->size); } } else { fprintf(f, "No memory blocks left allocated\n"); } } #endif char *copyString(const char *s) { char *s1; s1 = (char *)gmalloc((int)strlen(s) + 1); strcpy(s1, s); return s1; } xpdf-3.03/goo/Makefile.dep0000644000076400007640000000000011622305345014674 0ustar derekndereknxpdf-3.03/goo/vms_make.com0000644000076400007640000000377311622305345015013 0ustar dereknderekn$!======================================================================== $! $! Goo library compile script for VMS. $! $! Written by Patrick Moreau, Martin P.J. Zinser. $! $! Copyright 1996-2003 Glyph & Cog, LLC $! $!======================================================================== $! $ GOO_CXXOBJS = "GString.obj,gmempp.obj,gfile.obj,ghash.obj,glist.obj" $ GOO_CCOBJS = "gmem.obj,parseargs.obj,vms_directory.obj,vms_unix_times.obj" $! $ if f$extract(1,3,f$getsyi("Version")) .lts. "7.0" $ then $ GOO_CCOBJS = GOO_CCOBJS + ",vms_unlink.obj" $ endif $! $ i = 0 $ j = 0 $COMPILE_CXX_LOOP: $ file = f$element(i, ",",GOO_CXXOBJS) $ if file .eqs. "," then goto COMPILE_CC_LOOP $ i = i + 1 $ name = f$parse(file,,,"NAME") $ call make 'file "CXXCOMP ''name'.cc" - 'name'.cc $ goto COMPILE_CXX_LOOP $! $COMPILE_CC_LOOP: $ file = f$element(j, ",",GOO_CCOBJS) $ if file .eqs. "," then goto COMPILE_END $ j = j + 1 $ name = f$parse(file,,,"NAME") $ call make 'file "CCOMP ''name'.c" - 'name'.c $ goto COMPILE_CC_LOOP $! $COMPILE_END: $ call make libgoo.olb "lib/cre libgoo.olb ''GOO_CXXOBJS',''GOO_CCOBJS'" *.obj $! $ exit $! $MAKE: SUBROUTINE !SUBROUTINE TO CHECK DEPENDENCIES $ V = 'F$Verify(0) $! P1 = What we are trying to make $! P2 = Command to make it $! P3 - P8 What it depends on $ $ If F$Search(P1) .Eqs. "" Then Goto Makeit $ Time = F$CvTime(F$File(P1,"RDT")) $arg=3 $Loop: $ Argument = P'arg $ If Argument .Eqs. "" Then Goto Exit $ El=0 $Loop2: $ File = F$Element(El," ",Argument) $ If File .Eqs. " " Then Goto Endl $ AFile = "" $Loop3: $ OFile = AFile $ AFile = F$Search(File) $ If AFile .Eqs. "" .Or. AFile .Eqs. OFile Then Goto NextEl $ If F$CvTime(F$File(AFile,"RDT")) .Ges. Time Then Goto Makeit $ Goto Loop3 $NextEL: $ El = El + 1 $ Goto Loop2 $EndL: $ arg=arg+1 $ If arg .Le. 8 Then Goto Loop $ Goto Exit $ $Makeit: $ VV=F$VERIFY(0) $ write sys$output P2 $ 'P2 $ VV='F$Verify(VV) $Exit: $ If V Then Set Verify $ENDSUBROUTINE xpdf-3.03/goo/GHash.h0000644000076400007640000000424111622305345013643 0ustar dereknderekn//======================================================================== // // GHash.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GHASH_H #define GHASH_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" class GString; struct GHashBucket; struct GHashIter; //------------------------------------------------------------------------ class GHash { public: GHash(GBool deleteKeysA = gFalse); ~GHash(); void add(GString *key, void *val); void add(GString *key, int val); void replace(GString *key, void *val); void replace(GString *key, int val); void *lookup(GString *key); int lookupInt(GString *key); void *lookup(const char *key); int lookupInt(const char *key); void *remove(GString *key); int removeInt(GString *key); void *remove(const char *key); int removeInt(const char *key); int getLength() { return len; } void startIter(GHashIter **iter); GBool getNext(GHashIter **iter, GString **key, void **val); GBool getNext(GHashIter **iter, GString **key, int *val); void killIter(GHashIter **iter); private: void expand(); GHashBucket *find(GString *key, int *h); GHashBucket *find(const char *key, int *h); int hash(GString *key); int hash(const char *key); GBool deleteKeys; // set if key strings should be deleted int size; // number of buckets int len; // number of entries GHashBucket **tab; }; #define deleteGHash(hash, T) \ do { \ GHash *_hash = (hash); \ { \ GHashIter *_iter; \ GString *_key; \ void *_p; \ _hash->startIter(&_iter); \ while (_hash->getNext(&_iter, &_key, &_p)) { \ delete (T*)_p; \ } \ delete _hash; \ } \ } while(0) #endif xpdf-3.03/goo/vms_unix_time.h0000644000076400007640000000444411622305345015544 0ustar dereknderekn/* @(#)time.h 2.9 87/01/17 SMI; from UCB 7.1 6/4/86 */ /* Definitions of various structures used on UNIX for time-related syscalls. */ /* * Copyright (c) 1982, 1986 Regents of the University of California. * All rights reserved. The Berkeley software License Agreement * specifies the terms and conditions for redistribution. */ #ifndef _UNIX_TIME_ #define _UNIX_TIME_ #ifdef __cplusplus extern "C" { #endif /* * Structure returned by gettimeofday(2) system call, * and used in other calls. */ #ifndef __DECC struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; #else #if (__DECC_VER < 50200000) && (__VMS_VER < 70000000) struct timeval { long tv_sec; /* seconds */ long tv_usec; /* and microseconds */ }; #endif /* __DECC_VER */ #endif /* __DECC */ struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ int tz_dsttime; /* type of dst correction */ }; #define DST_NONE 0 /* not on dst */ #define DST_USA 1 /* USA style dst */ #define DST_AUST 2 /* Australian style dst */ #define DST_WET 3 /* Western European dst */ #define DST_MET 4 /* Middle European dst */ #define DST_EET 5 /* Eastern European dst */ #define DST_CAN 6 /* Canada */ #define DST_GB 7 /* Great Britain and Eire */ #define DST_RUM 8 /* Rumania */ #define DST_TUR 9 /* Turkey */ #define DST_AUSTALT 10 /* Australian style with shift in 1986 */ /* * Operations on timevals. * * NB: timercmp does not work for >= or <=. */ #define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec) #define timercmp(tvp, uvp, cmp) \ ((tvp)->tv_sec cmp (uvp)->tv_sec || \ (tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec) #define timerclear(tvp) (tvp)->tv_sec = (tvp)->tv_usec = 0 /* * Names of the interval timers, and structure * defining a timer setting. */ #define ITIMER_REAL 0 #define ITIMER_VIRTUAL 1 #define ITIMER_PROF 2 #ifndef __DECC struct itimerval { struct timeval it_interval; /* timer interval */ struct timeval it_value; /* current value */ }; #else #if (__DECC_VER < 50200000) && (__VMS_VER < 70000000) struct itimerval { struct timeval it_interval; /* timer interval */ struct timeval it_value; /* current value */ }; #endif /* __DECC_VER */ #endif /* __DECC */ #ifndef KERNEL #include #endif #ifdef __cplusplus } #endif #endif /*!_UNIX_TIME_*/ xpdf-3.03/goo/GList.cc0000644000076400007640000000432011622305345014027 0ustar dereknderekn//======================================================================== // // GList.cc // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include "gmem.h" #include "GList.h" //------------------------------------------------------------------------ // GList //------------------------------------------------------------------------ GList::GList() { size = 8; data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } GList::GList(int sizeA) { size = sizeA ? sizeA : 8; data = (void **)gmallocn(size, sizeof(void*)); length = 0; inc = 0; } GList::~GList() { gfree(data); } GList *GList::copy() { GList *ret; ret = new GList(length); ret->length = length; memcpy(ret->data, data, length * sizeof(void *)); ret->inc = inc; return ret; } void GList::append(void *p) { if (length >= size) { expand(); } data[length++] = p; } void GList::append(GList *list) { int i; while (length + list->length > size) { expand(); } for (i = 0; i < list->length; ++i) { data[length++] = list->data[i]; } } void GList::insert(int i, void *p) { if (length >= size) { expand(); } if (i < 0) { i = 0; } if (i < length) { memmove(data+i+1, data+i, (length - i) * sizeof(void *)); } data[i] = p; ++length; } void *GList::del(int i) { void *p; p = data[i]; if (i < length - 1) { memmove(data+i, data+i+1, (length - i - 1) * sizeof(void *)); } --length; if (size - length >= ((inc > 0) ? inc : size/2)) { shrink(); } return p; } void GList::sort(int (*cmp)(const void *obj1, const void *obj2)) { qsort(data, length, sizeof(void *), cmp); } void GList::reverse() { void *t; int n, i; n = length / 2; for (i = 0; i < n; ++i) { t = data[i]; data[i] = data[length - 1 - i]; data[length - 1 - i] = t; } } void GList::expand() { size += (inc > 0) ? inc : size; data = (void **)greallocn(data, size, sizeof(void*)); } void GList::shrink() { size -= (inc > 0) ? inc : size/2; data = (void **)greallocn(data, size, sizeof(void*)); } xpdf-3.03/goo/vms_sys_dirent.h0000644000076400007640000000317411622305345015725 0ustar dereknderekn/* @(#)dirent.h 1.4 89/06/16 SMI */ /* * Filesystem-independent directory information. * Directory entry structures are of variable length. * Each directory entry is a struct dirent containing its file number, the * offset of the next entry (a cookie interpretable only the filesystem * type that generated it), the length of the entry, and the length of the * name contained in the entry. These are followed by the name. The * entire entry is padded with null bytes to a 4 byte boundary. All names * are guaranteed null terminated. The maximum length of a name in a * directory is MAXNAMLEN, plus a null byte. */ #ifndef __sys_dirent_h #define __sys_dirent_h #ifdef __cplusplus extern "C" { #endif #define dirent GOO_dirent struct dirent { long d_off; /* offset of next disk dir entry */ unsigned long d_fileno; /* file number of entry */ unsigned short d_reclen; /* length of this record */ unsigned short d_namlen; /* length of string in d_name */ char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */ }; #ifndef _POSIX_SOURCE /* * It's unlikely to change, but make sure that sizeof d_name above is * at least MAXNAMLEN + 1 (more may be added for padding). */ #define MAXNAMLEN 255 /* * The macro DIRSIZ(dp) gives the minimum amount of space required to represent * a directory entry. For any directory entry dp->d_reclen >= DIRSIZ(dp). * Specific filesystem types may use this macro to construct the value * for d_reclen. */ #undef DIRSIZ #define DIRSIZ(dp) \ (((sizeof(struct dirent) - (MAXNAMLEN+1) + ((dp)->d_namlen+1)) +3) & ~3) #endif /* !_POSIX_SOURCE */ #ifdef __cplusplus } #endif #endif /* !__sys_dirent_h */ xpdf-3.03/goo/gmempp.cc0000644000076400007640000000106011622305345014270 0ustar dereknderekn//======================================================================== // // gmempp.cc // // Use gmalloc/gfree for C++ new/delete operators. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #include "gmem.h" #ifdef DEBUG_MEM void *operator new(size_t size) { return gmalloc((int)size); } void *operator new[](size_t size) { return gmalloc((int)size); } void operator delete(void *p) { gfree(p); } void operator delete[](void *p) { gfree(p); } #endif xpdf-3.03/goo/vms_dirent.h0000644000076400007640000000272111622305345015024 0ustar dereknderekn/* @(#)dirent.h 1.7 89/06/25 SMI */ /* * Filesystem-independent directory information. */ #ifndef __dirent_h #define __dirent_h #ifdef __cplusplus extern "C" { #endif /* Make sure we don't get the V7 RTL dirent functions. These are broken. */ #ifndef __CRTL_VER # define __CRTL_VER __VMS_VER #endif #if __CRTL_VER >= 70000000 #include #endif #include #define opendir goo_opendir #define readdir goo_readdir #define closedir goo_closedir #define seekdir goo_seekdir #define telldir goo_telldir #define rewinddir goo_rewindir #define DIR GOO_DIR #ifndef _POSIX_SOURCE #define d_ino d_fileno /* compatability */ #ifndef NULL #define NULL 0 #endif #endif /* !_POSIX_SOURCE */ /* * Definitions for library routines operating on directories. */ typedef struct __dirdesc { unsigned long dd_fd; /* file descriptor */ long dd_loc; /* buf offset of entry from last readddir() */ long dd_size; /* amount of valid data in buffer */ long dd_bsize; /* amount of entries read at a time */ long dd_off; /* Current offset in dir (for telldir) */ char *dd_buf; /* directory data buffer */ } DIR; #include "vms_sys_dirent.h" extern DIR *opendir(char *dirname); extern struct dirent *readdir(DIR *dirp); extern void closedir(DIR *dirp); #ifndef _POSIX_SOURCE extern void seekdir(DIR *dirp, int loc); extern long telldir(DIR *dirp); #endif /* POSIX_SOURCE */ extern void rewinddir(DIR *dirp); #ifdef __cplusplus } #endif #endif /* !__dirent_h */ xpdf-3.03/goo/GString.cc0000644000076400007640000003770311622305345014375 0ustar dereknderekn//======================================================================== // // GString.cc // // Simple variable-length string type. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include #include #include #include #include #include "gmem.h" #include "GString.h" //------------------------------------------------------------------------ union GStringFormatArg { int i; Guint ui; long l; Gulong ul; #ifdef LLONG_MAX long long ll; #endif #ifdef ULLONG_MAX unsigned long long ull; #endif double f; char c; char *s; GString *gs; }; enum GStringFormatType { fmtIntDecimal, fmtIntHex, fmtIntOctal, fmtIntBinary, fmtUIntDecimal, fmtUIntHex, fmtUIntOctal, fmtUIntBinary, fmtLongDecimal, fmtLongHex, fmtLongOctal, fmtLongBinary, fmtULongDecimal, fmtULongHex, fmtULongOctal, fmtULongBinary, #ifdef LLONG_MAX fmtLongLongDecimal, fmtLongLongHex, fmtLongLongOctal, fmtLongLongBinary, #endif #ifdef ULLONG_MAX fmtULongLongDecimal, fmtULongLongHex, fmtULongLongOctal, fmtULongLongBinary, #endif fmtDouble, fmtDoubleTrim, fmtChar, fmtString, fmtGString, fmtSpace }; static const char *formatStrings[] = { "d", "x", "o", "b", "ud", "ux", "uo", "ub", "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb", #ifdef LLONG_MAX "lld", "llx", "llo", "llb", #endif #ifdef ULLONG_MAX "ulld", "ullx", "ullo", "ullb", #endif "f", "g", "c", "s", "t", "w", NULL }; //------------------------------------------------------------------------ static inline int size(int len) { int delta; for (delta = 8; delta < len && delta < 0x100000; delta <<= 1) ; // this is ((len + 1) + (delta - 1)) & ~(delta - 1) return (len + delta) & ~(delta - 1); } inline void GString::resize(int length1) { char *s1; if (!s) { s = new char[size(length1)]; } else if (size(length1) != size(length)) { s1 = new char[size(length1)]; if (length1 < length) { memcpy(s1, s, length1); s1[length1] = '\0'; } else { memcpy(s1, s, length + 1); } delete[] s; s = s1; } } GString::GString() { s = NULL; resize(length = 0); s[0] = '\0'; } GString::GString(const char *sA) { int n = (int)strlen(sA); s = NULL; resize(length = n); memcpy(s, sA, n + 1); } GString::GString(const char *sA, int lengthA) { s = NULL; resize(length = lengthA); memcpy(s, sA, length * sizeof(char)); s[length] = '\0'; } GString::GString(GString *str, int idx, int lengthA) { s = NULL; resize(length = lengthA); memcpy(s, str->getCString() + idx, length); s[length] = '\0'; } GString::GString(GString *str) { s = NULL; resize(length = str->getLength()); memcpy(s, str->getCString(), length + 1); } GString::GString(GString *str1, GString *str2) { int n1 = str1->getLength(); int n2 = str2->getLength(); s = NULL; resize(length = n1 + n2); memcpy(s, str1->getCString(), n1); memcpy(s + n1, str2->getCString(), n2 + 1); } GString *GString::fromInt(int x) { char buf[24]; // enough space for 64-bit ints plus a little extra char *p; int len; formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len); return new GString(p, len); } GString *GString::format(const char *fmt, ...) { va_list argList; GString *s; s = new GString(); va_start(argList, fmt); s->appendfv(fmt, argList); va_end(argList); return s; } GString *GString::formatv(const char *fmt, va_list argList) { GString *s; s = new GString(); s->appendfv(fmt, argList); return s; } GString::~GString() { delete[] s; } GString *GString::clear() { s[length = 0] = '\0'; resize(0); return this; } GString *GString::append(char c) { resize(length + 1); s[length++] = c; s[length] = '\0'; return this; } GString *GString::append(GString *str) { int n = str->getLength(); resize(length + n); memcpy(s + length, str->getCString(), n + 1); length += n; return this; } GString *GString::append(const char *str) { int n = (int)strlen(str); resize(length + n); memcpy(s + length, str, n + 1); length += n; return this; } GString *GString::append(const char *str, int lengthA) { resize(length + lengthA); memcpy(s + length, str, lengthA); length += lengthA; s[length] = '\0'; return this; } GString *GString::appendf(const char *fmt, ...) { va_list argList; va_start(argList, fmt); appendfv(fmt, argList); va_end(argList); return this; } GString *GString::appendfv(const char *fmt, va_list argList) { GStringFormatArg *args; int argsLen, argsSize; GStringFormatArg arg; int idx, width, prec; GBool reverseAlign, zeroFill; GStringFormatType ft; char buf[65]; int len, i; const char *p0, *p1; char *str; argsLen = 0; argsSize = 8; args = (GStringFormatArg *)gmallocn(argsSize, sizeof(GStringFormatArg)); p0 = fmt; while (*p0) { if (*p0 == '{') { ++p0; if (*p0 == '{') { ++p0; append('{'); } else { // parse the format string if (!(*p0 >= '0' && *p0 <= '9')) { break; } idx = *p0 - '0'; for (++p0; *p0 >= '0' && *p0 <= '9'; ++p0) { idx = 10 * idx + (*p0 - '0'); } if (*p0 != ':') { break; } ++p0; if (*p0 == '-') { reverseAlign = gTrue; ++p0; } else { reverseAlign = gFalse; } width = 0; zeroFill = *p0 == '0'; for (; *p0 >= '0' && *p0 <= '9'; ++p0) { width = 10 * width + (*p0 - '0'); } if (width < 0) { width = 0; } if (*p0 == '.') { ++p0; prec = 0; for (; *p0 >= '0' && *p0 <= '9'; ++p0) { prec = 10 * prec + (*p0 - '0'); } } else { prec = 0; } for (ft = (GStringFormatType)0; formatStrings[ft]; ft = (GStringFormatType)(ft + 1)) { if (!strncmp(p0, formatStrings[ft], strlen(formatStrings[ft]))) { break; } } if (!formatStrings[ft]) { break; } p0 += strlen(formatStrings[ft]); if (*p0 != '}') { break; } ++p0; // fetch the argument if (idx > argsLen) { break; } if (idx == argsLen) { if (argsLen == argsSize) { argsSize *= 2; args = (GStringFormatArg *)greallocn(args, argsSize, sizeof(GStringFormatArg)); } switch (ft) { case fmtIntDecimal: case fmtIntHex: case fmtIntOctal: case fmtIntBinary: case fmtSpace: args[argsLen].i = va_arg(argList, int); break; case fmtUIntDecimal: case fmtUIntHex: case fmtUIntOctal: case fmtUIntBinary: args[argsLen].ui = va_arg(argList, Guint); break; case fmtLongDecimal: case fmtLongHex: case fmtLongOctal: case fmtLongBinary: args[argsLen].l = va_arg(argList, long); break; case fmtULongDecimal: case fmtULongHex: case fmtULongOctal: case fmtULongBinary: args[argsLen].ul = va_arg(argList, Gulong); break; #ifdef LLONG_MAX case fmtLongLongDecimal: case fmtLongLongHex: case fmtLongLongOctal: case fmtLongLongBinary: args[argsLen].ll = va_arg(argList, long long); break; #endif #ifdef ULLONG_MAX case fmtULongLongDecimal: case fmtULongLongHex: case fmtULongLongOctal: case fmtULongLongBinary: args[argsLen].ull = va_arg(argList, unsigned long long); break; #endif case fmtDouble: case fmtDoubleTrim: args[argsLen].f = va_arg(argList, double); break; case fmtChar: args[argsLen].c = (char)va_arg(argList, int); break; case fmtString: args[argsLen].s = va_arg(argList, char *); break; case fmtGString: args[argsLen].gs = va_arg(argList, GString *); break; } ++argsLen; } // format the argument arg = args[idx]; switch (ft) { case fmtIntDecimal: formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtIntHex: formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtIntOctal: formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtIntBinary: formatInt(arg.i, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; case fmtUIntDecimal: formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtUIntHex: formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtUIntOctal: formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtUIntBinary: formatUInt(arg.ui, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; case fmtLongDecimal: formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtLongHex: formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtLongOctal: formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtLongBinary: formatInt(arg.l, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; case fmtULongDecimal: formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtULongHex: formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtULongOctal: formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtULongBinary: formatUInt(arg.ul, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; #ifdef LLONG_MAX case fmtLongLongDecimal: formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtLongLongHex: formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtLongLongOctal: formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtLongLongBinary: formatInt(arg.ll, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; #endif #ifdef ULLONG_MAX case fmtULongLongDecimal: formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 10, &str, &len); break; case fmtULongLongHex: formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 16, &str, &len); break; case fmtULongLongOctal: formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 8, &str, &len); break; case fmtULongLongBinary: formatUInt(arg.ull, buf, sizeof(buf), zeroFill, width, 2, &str, &len); break; #endif case fmtDouble: formatDouble(arg.f, buf, sizeof(buf), prec, gFalse, &str, &len); break; case fmtDoubleTrim: formatDouble(arg.f, buf, sizeof(buf), prec, gTrue, &str, &len); break; case fmtChar: buf[0] = arg.c; str = buf; len = 1; reverseAlign = !reverseAlign; break; case fmtString: str = arg.s; len = (int)strlen(str); reverseAlign = !reverseAlign; break; case fmtGString: str = arg.gs->getCString(); len = arg.gs->getLength(); reverseAlign = !reverseAlign; break; case fmtSpace: str = buf; len = 0; width = arg.i; break; } // append the formatted arg, handling width and alignment if (!reverseAlign && len < width) { for (i = len; i < width; ++i) { append(' '); } } append(str, len); if (reverseAlign && len < width) { for (i = len; i < width; ++i) { append(' '); } } } } else if (*p0 == '}') { ++p0; if (*p0 == '}') { ++p0; } append('}'); } else { for (p1 = p0 + 1; *p1 && *p1 != '{' && *p1 != '}'; ++p1) ; append(p0, (int)(p1 - p0)); p0 = p1; } } gfree(args); return this; } #ifdef LLONG_MAX void GString::formatInt(long long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len) { #else void GString::formatInt(long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len) { #endif static char vals[17] = "0123456789abcdef"; GBool neg; int start, i, j; i = bufSize; if ((neg = x < 0)) { x = -x; } start = neg ? 1 : 0; if (x == 0) { buf[--i] = '0'; } else { while (i > start && x) { buf[--i] = vals[x % base]; x /= base; } } if (zeroFill) { for (j = bufSize - i; i > start && j < width - start; ++j) { buf[--i] = '0'; } } if (neg) { buf[--i] = '-'; } *p = buf + i; *len = bufSize - i; } #ifdef ULLONG_MAX void GString::formatUInt(unsigned long long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len) { #else void GString::formatUInt(Gulong x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len) { #endif static char vals[17] = "0123456789abcdef"; int i, j; i = bufSize; if (x == 0) { buf[--i] = '0'; } else { while (i > 0 && x) { buf[--i] = vals[x % base]; x /= base; } } if (zeroFill) { for (j = bufSize - i; i > 0 && j < width; ++j) { buf[--i] = '0'; } } *p = buf + i; *len = bufSize - i; } void GString::formatDouble(double x, char *buf, int bufSize, int prec, GBool trim, char **p, int *len) { GBool neg, started; double x2; int d, i, j; if ((neg = x < 0)) { x = -x; } x = floor(x * pow(10.0, prec) + 0.5); i = bufSize; started = !trim; for (j = 0; j < prec && i > 1; ++j) { x2 = floor(0.1 * (x + 0.5)); d = (int)floor(x - 10 * x2 + 0.5); if (started || d != 0) { buf[--i] = '0' + d; started = gTrue; } x = x2; } if (i > 1 && started) { buf[--i] = '.'; } if (i > 1) { do { x2 = floor(0.1 * (x + 0.5)); d = (int)floor(x - 10 * x2 + 0.5); buf[--i] = '0' + d; x = x2; } while (i > 1 && x); } if (neg) { buf[--i] = '-'; } *p = buf + i; *len = bufSize - i; } GString *GString::insert(int i, char c) { int j; resize(length + 1); for (j = length + 1; j > i; --j) s[j] = s[j-1]; s[i] = c; ++length; return this; } GString *GString::insert(int i, GString *str) { int n = str->getLength(); int j; resize(length + n); for (j = length; j >= i; --j) s[j+n] = s[j]; memcpy(s+i, str->getCString(), n); length += n; return this; } GString *GString::insert(int i, const char *str) { int n = (int)strlen(str); int j; resize(length + n); for (j = length; j >= i; --j) s[j+n] = s[j]; memcpy(s+i, str, n); length += n; return this; } GString *GString::insert(int i, const char *str, int lengthA) { int j; resize(length + lengthA); for (j = length; j >= i; --j) s[j+lengthA] = s[j]; memcpy(s+i, str, lengthA); length += lengthA; return this; } GString *GString::del(int i, int n) { int j; if (i >= 0 && n > 0 && i + n > 0) { if (i + n > length) { n = length - i; } for (j = i; j <= length - n; ++j) { s[j] = s[j + n]; } resize(length -= n); } return this; } GString *GString::upperCase() { int i; for (i = 0; i < length; ++i) { if (islower(s[i])) s[i] = toupper(s[i]); } return this; } GString *GString::lowerCase() { int i; for (i = 0; i < length; ++i) { if (isupper(s[i])) s[i] = tolower(s[i]); } return this; } int GString::cmp(GString *str) { int n1, n2, i, x; char *p1, *p2; n1 = length; n2 = str->length; for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2; ++i, ++p1, ++p2) { x = *p1 - *p2; if (x != 0) { return x; } } return n1 - n2; } int GString::cmpN(GString *str, int n) { int n1, n2, i, x; char *p1, *p2; n1 = length; n2 = str->length; for (i = 0, p1 = s, p2 = str->s; i < n1 && i < n2 && i < n; ++i, ++p1, ++p2) { x = *p1 - *p2; if (x != 0) { return x; } } if (i == n) { return 0; } return n1 - n2; } int GString::cmp(const char *sA) { int n1, i, x; const char *p1, *p2; n1 = length; for (i = 0, p1 = s, p2 = sA; i < n1 && *p2; ++i, ++p1, ++p2) { x = *p1 - *p2; if (x != 0) { return x; } } if (i < n1) { return 1; } if (*p2) { return -1; } return 0; } int GString::cmpN(const char *sA, int n) { int n1, i, x; const char *p1, *p2; n1 = length; for (i = 0, p1 = s, p2 = sA; i < n1 && *p2 && i < n; ++i, ++p1, ++p2) { x = *p1 - *p2; if (x != 0) { return x; } } if (i == n) { return 0; } if (i < n1) { return 1; } if (*p2) { return -1; } return 0; } xpdf-3.03/goo/vms_directory.c0000644000076400007640000001106011622305345015532 0ustar dereknderekn/* * DIRECTORY.C - VMS emulation routines for UNIX Directory * callable routines * * Author: Patrick L. Mahan * Location: TGV, Inc * Date: 19-November-1991 * * Purpose: Provides emulation of the BSD directory routines * which are used by some of the X11 R4 release * software. * * Side effects: This is only a partial emulation. Not all of * the required information is passed to the user. * * Modification History * * Date | Who | Version | History * ------------+-----------+---------------+---------------------------- * 19-Nov-1991 | PLM | 1.0 | First Write * 20-Apr-1992 | PLM | 1.1 | Added validation check for * | | | for the directory */ #include #include #include #include #include #include #include "vms_dirent.h" #define NOWILD 0x00000001 #define MULTIPLE 0x00000002 static unsigned long context = 0; static struct dsc$descriptor_s *create_descriptor ( name ) char *name; { struct dsc$descriptor_s *retdescrip; retdescrip = (struct dsc$descriptor_s *)calloc(1, sizeof(struct dsc$descriptor_s)); if (retdescrip == NULL) return ((struct dsc$descriptor_s *)NULL); retdescrip->dsc$b_dtype = DSC$K_DTYPE_T; retdescrip->dsc$b_class = DSC$K_CLASS_S; retdescrip->dsc$w_length = strlen(name); retdescrip->dsc$a_pointer = name; return (retdescrip); } static int Check_Directory( dirname ) char *dirname; { static char *tmpdir, *cp; FILE *tfp; int status; status = 1; tmpdir = calloc(strlen(dirname)+15,sizeof(char)); strcpy(tmpdir, dirname); cp = strrchr(tmpdir, '.'); if (cp != NULL) { *cp = ']'; cp = strrchr(tmpdir, ']'); *cp = '.'; strcat(tmpdir, "dir"); } else { char *tmp1; tmp1 = calloc(strlen(dirname)+1,sizeof(char)); cp = strchr(tmpdir, '['); cp++; strcpy(tmp1, cp); cp = strrchr(tmp1, ']'); *cp = '\0'; cp = strchr(tmpdir, '['); cp++; *cp = '\0'; strcat(tmpdir, "000000]"); strcat(tmpdir, tmp1); strcat(tmpdir, ".dir"); } tfp = fopen(tmpdir, "r"); if (tfp == NULL) status = 0; fclose(tfp); return (status); } DIR *opendir( dirname ) char *dirname; { DIR *retdir; struct dsc$descriptor_s filedescriptor; char *filepathname; retdir = (DIR *) calloc(1, sizeof(DIR)); if (retdir == NULL) return ((DIR *)NULL); if (!Check_Directory(dirname)) return ((DIR *)NULL); filepathname = (char *)calloc(256, sizeof(char)); strcpy(filepathname, dirname); strcat(filepathname, "*.*.*"); retdir->dd_fd = (unsigned long) create_descriptor(filepathname); retdir->dd_loc = 0; retdir->dd_size = strlen(filepathname); retdir->dd_bsize = 0; retdir->dd_off = 0; retdir->dd_buf = filepathname; return (retdir); } struct dirent *readdir( dirp ) DIR *dirp; { static struct dirent *retdirent; struct dsc$descriptor_s retfilenamedesc; struct dsc$descriptor_s searchpathdesc = *((struct dsc$descriptor_s *)dirp->dd_fd); char retfilename[256]; char *sp; unsigned long istatus; unsigned long rms_status; unsigned long flags; retdirent = (struct dirent *)NULL; flags = MULTIPLE; retfilenamedesc.dsc$b_dtype = DSC$K_DTYPE_T; retfilenamedesc.dsc$b_class = DSC$K_CLASS_S; retfilenamedesc.dsc$w_length = 255; retfilenamedesc.dsc$a_pointer= retfilename; istatus = lib$find_file (&searchpathdesc, &retfilenamedesc, &dirp->dd_loc, 0, 0, &rms_status, &flags); if (!(istatus & 1) && (istatus != RMS$_NMF) && (istatus != RMS$_FNF)) { lib$signal (istatus); return (retdirent); } else if ((istatus == RMS$_NMF) || (istatus == RMS$_FNF)) return (retdirent); retfilename[retfilenamedesc.dsc$w_length] = '\0'; sp = strchr(retfilename, ' '); if (sp != NULL) *sp = '\0'; sp = strrchr(retfilename, ']'); if (sp != NULL) sp++; else sp = retfilename; retdirent = (struct dirent *)calloc(1, sizeof(struct dirent)); strcpy(retdirent->d_name, sp); retdirent->d_namlen = strlen(sp); retdirent->d_fileno = 0; retdirent->d_off = 0; retdirent->d_reclen = DIRSIZ(retdirent); return (retdirent); } long telldir( dirp ) DIR *dirp; { return(0); } void seekdir( dirp, loc ) DIR *dirp; int loc; { return; } void rewinddir( dirp ) DIR *dirp; { lib$find_file_end (&dirp->dd_loc); } void closedir( dirp ) DIR *dirp; { lib$find_file_end (&dirp->dd_loc); cfree ((void *) dirp->dd_fd); cfree (dirp->dd_buf); cfree (dirp); } xpdf-3.03/goo/gfile.h0000644000076400007640000000764611622305345013753 0ustar dereknderekn//======================================================================== // // gfile.h // // Miscellaneous file and directory name manipulation. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GFILE_H #define GFILE_H #include #include #include #if defined(WIN32) # include # ifdef FPTEX # include # else # include # endif #elif defined(ACORN) #elif defined(MACOS) # include #else # include # include # ifdef VMS # include "vms_dirent.h" # elif HAVE_DIRENT_H # include # define NAMLEN(d) strlen((d)->d_name) # else # define dirent direct # define NAMLEN(d) (d)->d_namlen # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif # endif #endif #include "gtypes.h" class GString; //------------------------------------------------------------------------ // Get home directory path. extern GString *getHomeDir(); // Get current directory. extern GString *getCurrentDir(); // Append a file name to a path string. may be an empty // string, denoting the current directory). Returns . extern GString *appendToPath(GString *path, const char *fileName); // Grab the path from the front of the file name. If there is no // directory component in , returns an empty string. extern GString *grabPath(char *fileName); // Is this an absolute path or file name? extern GBool isAbsolutePath(char *path); // Make this path absolute by prepending current directory (if path is // relative) or prepending user's directory (if path starts with '~'). extern GString *makePathAbsolute(GString *path); // Get the modification time for . Returns 0 if there is an // error. extern time_t getModTime(char *fileName); // Create a temporary file and open it for writing. If is not // NULL, it will be used as the file name extension. Returns both the // name and the file pointer. For security reasons, all writing // should be done to the returned file pointer; the file may be // reopened later for reading, but not for writing. The string // should be "w" or "wb". Returns true on success. extern GBool openTempFile(GString **name, FILE **f, const char *mode, char *ext); // Execute . Returns true on success. extern GBool executeCommand(char *cmd); #ifdef WIN32 // Convert a file name from Latin-1 to UTF-8. extern GString *fileNameToUTF8(char *path); // Convert a file name from UCS-2 to UTF-8. extern GString *fileNameToUTF8(wchar_t *path); #endif // Open a file. On Windows, this converts the path from UTF-8 to // UCS-2 and calls _wfopen (if available). On other OSes, this simply // calls fopen. extern FILE *openFile(const char *path, const char *mode); // Just like fgets, but handles Unix, Mac, and/or DOS end-of-line // conventions. extern char *getLine(char *buf, int size, FILE *f); //------------------------------------------------------------------------ // GDir and GDirEntry //------------------------------------------------------------------------ class GDirEntry { public: GDirEntry(char *dirPath, char *nameA, GBool doStat); ~GDirEntry(); GString *getName() { return name; } GBool isDir() { return dir; } private: GString *name; // dir/file name GBool dir; // is it a directory? }; class GDir { public: GDir(char *name, GBool doStatA = gTrue); ~GDir(); GDirEntry *getNextEntry(); void rewind(); private: GString *path; // directory path GBool doStat; // call stat() for each entry? #if defined(WIN32) WIN32_FIND_DATA ffd; HANDLE hnd; #elif defined(ACORN) #elif defined(MACOS) #else DIR *dir; // the DIR structure from opendir() #ifdef VMS GBool needParent; // need to return an entry for [-] #endif #endif }; #endif xpdf-3.03/goo/parseargs.h0000644000076400007640000000305711622305345014644 0ustar dereknderekn/* * parseargs.h * * Command line argument parser. * * Copyright 1996-2003 Glyph & Cog, LLC */ #ifndef PARSEARGS_H #define PARSEARGS_H #ifdef __cplusplus extern "C" { #endif #include "gtypes.h" /* * Argument kinds. */ typedef enum { argFlag, /* flag (present / not-present) */ /* [val: GBool *] */ argInt, /* integer arg */ /* [val: int *] */ argFP, /* floating point arg */ /* [val: double *] */ argString, /* string arg */ /* [val: char *] */ /* dummy entries -- these show up in the usage listing only; */ /* useful for X args, for example */ argFlagDummy, argIntDummy, argFPDummy, argStringDummy } ArgKind; /* * Argument descriptor. */ typedef struct { const char *arg; /* the command line switch */ ArgKind kind; /* kind of arg */ void *val; /* place to store value */ int size; /* for argString: size of string */ const char *usage; /* usage string */ } ArgDesc; /* * Parse command line. Removes all args which are found in the arg * descriptor list . Stops parsing if "--" is found (and removes * it). Returns gFalse if there was an error. */ extern GBool parseArgs(ArgDesc *args, int *argc, char *argv[]); /* * Print usage message, based on arg descriptor list. */ extern void printUsage(const char *program, const char *otherArgs, ArgDesc *args); /* * Check if a string is a valid integer or floating point number. */ extern GBool isInt(char *s); extern GBool isFP(char *s); #ifdef __cplusplus } #endif #endif xpdf-3.03/goo/vms_unix_times.c0000644000076400007640000000135011622305345015713 0ustar dereknderekn/* * UNIX-style Time Functions * */ #include #include #include #include "vms_unix_time.h" /* * gettimeofday(2) - Returns the current time * * NOTE: The timezone portion is useless on VMS. * Even on UNIX, it is only provided for backwards * compatibilty and is not guaranteed to be correct. */ #if (__VMS_VER < 70000000) int gettimeofday(tv, tz) struct timeval *tv; struct timezone *tz; { timeb_t tmp_time; ftime(&tmp_time); if (tv != NULL) { tv->tv_sec = tmp_time.time; tv->tv_usec = tmp_time.millitm * 1000; } if (tz != NULL) { tz->tz_minuteswest = tmp_time.timezone; tz->tz_dsttime = tmp_time.dstflag; } return (0); } /*** End gettimeofday() ***/ #endif xpdf-3.03/goo/GList.h0000644000076400007640000000524411622305345013677 0ustar dereknderekn//======================================================================== // // GList.h // // Copyright 2001-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GLIST_H #define GLIST_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include "gtypes.h" //------------------------------------------------------------------------ // GList //------------------------------------------------------------------------ class GList { public: // Create an empty list. GList(); // Create an empty list with space for elements. GList(int sizeA); // Destructor - does not free pointed-to objects. ~GList(); //----- general // Get the number of elements. int getLength() { return length; } // Returns a (shallow) copy of this list. GList *copy(); //----- ordered list support // Return the th element. // Assumes 0 <= i < length. void *get(int i) { return data[i]; } // Replace the th element. // Assumes 0 <= i < length. void put(int i, void *p) { data[i] = p; } // Append an element to the end of the list. void append(void *p); // Append another list to the end of this one. void append(GList *list); // Insert an element at index . // Assumes 0 <= i <= length. void insert(int i, void *p); // Deletes and returns the element at index . // Assumes 0 <= i < length. void *del(int i); // Sort the list accoring to the given comparison function. // NB: this sorts an array of pointers, so the pointer args need to // be double-dereferenced. void sort(int (*cmp)(const void *ptr1, const void *ptr2)); // Reverse the list. void reverse(); //----- control // Set allocation increment to . If inc > 0, that many // elements will be allocated every time the list is expanded. // If inc <= 0, the list will be doubled in size. void setAllocIncr(int incA) { inc = incA; } private: void expand(); void shrink(); void **data; // the list elements int size; // size of data array int length; // number of elements on list int inc; // allocation increment }; #define deleteGList(list, T) \ do { \ GList *_list = (list); \ { \ int _i; \ for (_i = 0; _i < _list->getLength(); ++_i) { \ delete (T*)_list->get(_i); \ } \ delete _list; \ } \ } while (0) #endif xpdf-3.03/goo/gfile.cc0000644000076400007640000004321311622305345014077 0ustar dereknderekn//======================================================================== // // gfile.cc // // Miscellaneous file and directory name manipulation. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #include #ifdef WIN32 # include #else # if defined(MACOS) # include # elif !defined(ACORN) # include # include # include # endif # include # include # include # if !defined(VMS) && !defined(ACORN) && !defined(MACOS) # include # endif # if defined(VMS) && (__DECCXX_VER < 50200000) # include # endif #endif // WIN32 #include "GString.h" #include "gfile.h" // Some systems don't define this, so just make it something reasonably // large. #ifndef PATH_MAX #define PATH_MAX 1024 #endif //------------------------------------------------------------------------ GString *getHomeDir() { #ifdef VMS //---------- VMS ---------- return new GString("SYS$LOGIN:"); #elif defined(__EMX__) || defined(WIN32) //---------- OS/2+EMX and Win32 ---------- char *s; GString *ret; if ((s = getenv("HOME"))) ret = new GString(s); else ret = new GString("."); return ret; #elif defined(ACORN) //---------- RISCOS ---------- return new GString("@"); #elif defined(MACOS) //---------- MacOS ---------- return new GString(":"); #else //---------- Unix ---------- char *s; struct passwd *pw; GString *ret; if ((s = getenv("HOME"))) { ret = new GString(s); } else { if ((s = getenv("USER"))) pw = getpwnam(s); else pw = getpwuid(getuid()); if (pw) ret = new GString(pw->pw_dir); else ret = new GString("."); } return ret; #endif } GString *getCurrentDir() { char buf[PATH_MAX+1]; #if defined(__EMX__) if (_getcwd2(buf, sizeof(buf))) #elif defined(WIN32) if (GetCurrentDirectory(sizeof(buf), buf)) #elif defined(ACORN) if (strcpy(buf, "@")) #elif defined(MACOS) if (strcpy(buf, ":")) #else if (getcwd(buf, sizeof(buf))) #endif return new GString(buf); return new GString(); } GString *appendToPath(GString *path, const char *fileName) { #if defined(VMS) //---------- VMS ---------- //~ this should handle everything necessary for file //~ requesters, but it's certainly not complete char *p0, *p1, *p2; char *q1; p0 = path->getCString(); p1 = p0 + path->getLength() - 1; if (!strcmp(fileName, "-")) { if (*p1 == ']') { for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ; if (*p2 == '[') ++p2; path->del(p2 - p0, p1 - p2); } else if (*p1 == ':') { path->append("[-]"); } else { path->clear(); path->append("[-]"); } } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) { if (*p1 == ']') { path->insert(p1 - p0, '.'); path->insert(p1 - p0 + 1, fileName, q1 - fileName); } else if (*p1 == ':') { path->append('['); path->append(']'); path->append(fileName, q1 - fileName); } else { path->clear(); path->append(fileName, q1 - fileName); } } else { if (*p1 != ']' && *p1 != ':') path->clear(); path->append(fileName); } return path; #elif defined(WIN32) //---------- Win32 ---------- GString *tmp; char buf[256]; char *fp; tmp = new GString(path); tmp->append('/'); tmp->append(fileName); GetFullPathName(tmp->getCString(), sizeof(buf), buf, &fp); delete tmp; path->clear(); path->append(buf); return path; #elif defined(ACORN) //---------- RISCOS ---------- char *p; int i; path->append("."); i = path->getLength(); path->append(fileName); for (p = path->getCString() + i; *p; ++p) { if (*p == '/') { *p = '.'; } else if (*p == '.') { *p = '/'; } } return path; #elif defined(MACOS) //---------- MacOS ---------- char *p; int i; path->append(":"); i = path->getLength(); path->append(fileName); for (p = path->getCString() + i; *p; ++p) { if (*p == '/') { *p = ':'; } else if (*p == '.') { *p = ':'; } } return path; #elif defined(__EMX__) //---------- OS/2+EMX ---------- int i; // appending "." does nothing if (!strcmp(fileName, ".")) return path; // appending ".." goes up one directory if (!strcmp(fileName, "..")) { for (i = path->getLength() - 2; i >= 0; --i) { if (path->getChar(i) == '/' || path->getChar(i) == '\\' || path->getChar(i) == ':') break; } if (i <= 0) { if (path->getChar(0) == '/' || path->getChar(0) == '\\') { path->del(1, path->getLength() - 1); } else if (path->getLength() >= 2 && path->getChar(1) == ':') { path->del(2, path->getLength() - 2); } else { path->clear(); path->append(".."); } } else { if (path->getChar(i-1) == ':') ++i; path->del(i, path->getLength() - i); } return path; } // otherwise, append "/" and new path component if (path->getLength() > 0 && path->getChar(path->getLength() - 1) != '/' && path->getChar(path->getLength() - 1) != '\\') path->append('/'); path->append(fileName); return path; #else //---------- Unix ---------- int i; // appending "." does nothing if (!strcmp(fileName, ".")) return path; // appending ".." goes up one directory if (!strcmp(fileName, "..")) { for (i = path->getLength() - 2; i >= 0; --i) { if (path->getChar(i) == '/') break; } if (i <= 0) { if (path->getChar(0) == '/') { path->del(1, path->getLength() - 1); } else { path->clear(); path->append(".."); } } else { path->del(i, path->getLength() - i); } return path; } // otherwise, append "/" and new path component if (path->getLength() > 0 && path->getChar(path->getLength() - 1) != '/') path->append('/'); path->append(fileName); return path; #endif } GString *grabPath(char *fileName) { #ifdef VMS //---------- VMS ---------- char *p; if ((p = strrchr(fileName, ']'))) return new GString(fileName, p + 1 - fileName); if ((p = strrchr(fileName, ':'))) return new GString(fileName, p + 1 - fileName); return new GString(); #elif defined(__EMX__) || defined(WIN32) //---------- OS/2+EMX and Win32 ---------- char *p; if ((p = strrchr(fileName, '/'))) return new GString(fileName, (int)(p - fileName)); if ((p = strrchr(fileName, '\\'))) return new GString(fileName, (int)(p - fileName)); if ((p = strrchr(fileName, ':'))) return new GString(fileName, (int)(p + 1 - fileName)); return new GString(); #elif defined(ACORN) //---------- RISCOS ---------- char *p; if ((p = strrchr(fileName, '.'))) return new GString(fileName, p - fileName); return new GString(); #elif defined(MACOS) //---------- MacOS ---------- char *p; if ((p = strrchr(fileName, ':'))) return new GString(fileName, p - fileName); return new GString(); #else //---------- Unix ---------- char *p; if ((p = strrchr(fileName, '/'))) return new GString(fileName, p - fileName); return new GString(); #endif } GBool isAbsolutePath(char *path) { #ifdef VMS //---------- VMS ---------- return strchr(path, ':') || (path[0] == '[' && path[1] != '.' && path[1] != '-'); #elif defined(__EMX__) || defined(WIN32) //---------- OS/2+EMX and Win32 ---------- return path[0] == '/' || path[0] == '\\' || path[1] == ':'; #elif defined(ACORN) //---------- RISCOS ---------- return path[0] == '$'; #elif defined(MACOS) //---------- MacOS ---------- return path[0] != ':'; #else //---------- Unix ---------- return path[0] == '/'; #endif } GString *makePathAbsolute(GString *path) { #ifdef VMS //---------- VMS ---------- char buf[PATH_MAX+1]; if (!isAbsolutePath(path->getCString())) { if (getcwd(buf, sizeof(buf))) { path->insert(0, buf); } } return path; #elif defined(WIN32) //---------- Win32 ---------- char buf[_MAX_PATH]; char *fp; buf[0] = '\0'; if (!GetFullPathName(path->getCString(), _MAX_PATH, buf, &fp)) { path->clear(); return path; } path->clear(); path->append(buf); return path; #elif defined(ACORN) //---------- RISCOS ---------- path->insert(0, '@'); return path; #elif defined(MACOS) //---------- MacOS ---------- path->del(0, 1); return path; #else //---------- Unix and OS/2+EMX ---------- struct passwd *pw; char buf[PATH_MAX+1]; GString *s; char *p1, *p2; int n; if (path->getChar(0) == '~') { if (path->getChar(1) == '/' || #ifdef __EMX__ path->getChar(1) == '\\' || #endif path->getLength() == 1) { path->del(0, 1); s = getHomeDir(); path->insert(0, s); delete s; } else { p1 = path->getCString() + 1; #ifdef __EMX__ for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ; #else for (p2 = p1; *p2 && *p2 != '/'; ++p2) ; #endif if ((n = p2 - p1) > PATH_MAX) n = PATH_MAX; strncpy(buf, p1, n); buf[n] = '\0'; if ((pw = getpwnam(buf))) { path->del(0, p2 - p1 + 1); path->insert(0, pw->pw_dir); } } } else if (!isAbsolutePath(path->getCString())) { if (getcwd(buf, sizeof(buf))) { #ifndef __EMX__ path->insert(0, '/'); #endif path->insert(0, buf); } } return path; #endif } time_t getModTime(char *fileName) { #ifdef WIN32 //~ should implement this, but it's (currently) only used in xpdf return 0; #else struct stat statBuf; if (stat(fileName, &statBuf)) { return 0; } return statBuf.st_mtime; #endif } GBool openTempFile(GString **name, FILE **f, const char *mode, char *ext) { #if defined(WIN32) //---------- Win32 ---------- char *tempDir; GString *s, *s2; FILE *f2; int t, i; // this has the standard race condition problem, but I haven't found // a better way to generate temp file names with extensions on // Windows if ((tempDir = getenv("TEMP"))) { s = new GString(tempDir); s->append('\\'); } else { s = new GString(); } s->appendf("x_{0:d}_{1:d}_", (int)GetCurrentProcessId(), (int)GetCurrentThreadId()); t = (int)time(NULL); for (i = 0; i < 1000; ++i) { s2 = s->copy()->appendf("{0:d}", t + i); if (ext) { s2->append(ext); } if (!(f2 = fopen(s2->getCString(), "r"))) { if (!(f2 = fopen(s2->getCString(), mode))) { delete s2; delete s; return gFalse; } *name = s2; *f = f2; delete s; return gTrue; } fclose(f2); delete s2; } delete s; return gFalse; #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) //---------- non-Unix ---------- char *s; // There is a security hole here: an attacker can create a symlink // with this file name after the tmpnam call and before the fopen // call. I will happily accept fixes to this function for non-Unix // OSs. if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); if (ext) { (*name)->append(ext); } if (!(*f = fopen((*name)->getCString(), mode))) { delete (*name); *name = NULL; return gFalse; } return gTrue; #else //---------- Unix ---------- char *s; int fd; if (ext) { #if HAVE_MKSTEMPS if ((s = getenv("TMPDIR"))) { *name = new GString(s); } else { *name = new GString("/tmp"); } (*name)->append("/XXXXXX")->append(ext); fd = mkstemps((*name)->getCString(), strlen(ext)); #else if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); (*name)->append(ext); fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); #endif } else { #if HAVE_MKSTEMP if ((s = getenv("TMPDIR"))) { *name = new GString(s); } else { *name = new GString("/tmp"); } (*name)->append("/XXXXXX"); fd = mkstemp((*name)->getCString()); #else // HAVE_MKSTEMP if (!(s = tmpnam(NULL))) { return gFalse; } *name = new GString(s); fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600); #endif // HAVE_MKSTEMP } if (fd < 0 || !(*f = fdopen(fd, mode))) { delete *name; *name = NULL; return gFalse; } return gTrue; #endif } GBool executeCommand(char *cmd) { #ifdef VMS return system(cmd) ? gTrue : gFalse; #else return system(cmd) ? gFalse : gTrue; #endif } #ifdef WIN32 GString *fileNameToUTF8(char *path) { GString *s; char *p; s = new GString(); for (p = path; *p; ++p) { if (*p & 0x80) { s->append((char)(0xc0 | ((*p >> 6) & 0x03))); s->append((char)(0x80 | (*p & 0x3f))); } else { s->append(*p); } } return s; } GString *fileNameToUTF8(wchar_t *path) { GString *s; wchar_t *p; s = new GString(); for (p = path; *p; ++p) { if (*p < 0x80) { s->append((char)*p); } else if (*p < 0x800) { s->append((char)(0xc0 | ((*p >> 6) & 0x1f))); s->append((char)(0x80 | (*p & 0x3f))); } else { s->append((char)(0xe0 | ((*p >> 12) & 0x0f))); s->append((char)(0x80 | ((*p >> 6) & 0x3f))); s->append((char)(0x80 | (*p & 0x3f))); } } return s; } #endif FILE *openFile(const char *path, const char *mode) { #ifdef WIN32 OSVERSIONINFO version; wchar_t wPath[_MAX_PATH + 1]; char nPath[_MAX_PATH + 1]; wchar_t wMode[8]; const char *p; int i; // NB: _wfopen is only available in NT version.dwOSVersionInfoSize = sizeof(version); GetVersionEx(&version); if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { for (p = path, i = 0; *p && i < _MAX_PATH; ++i) { if ((p[0] & 0xe0) == 0xc0 && p[1] && (p[1] & 0xc0) == 0x80) { wPath[i] = (wchar_t)(((p[0] & 0x1f) << 6) | (p[1] & 0x3f)); p += 2; } else if ((p[0] & 0xf0) == 0xe0 && p[1] && (p[1] & 0xc0) == 0x80 && p[2] && (p[2] & 0xc0) == 0x80) { wPath[i] = (wchar_t)(((p[0] & 0x0f) << 12) | ((p[1] & 0x3f) << 6) | (p[2] & 0x3f)); p += 3; } else { wPath[i] = (wchar_t)(p[0] & 0xff); p += 1; } } wPath[i] = (wchar_t)0; for (i = 0; mode[i] && i < sizeof(mode) - 1; ++i) { wMode[i] = (wchar_t)(mode[i] & 0xff); } wMode[i] = (wchar_t)0; return _wfopen(wPath, wMode); } else { for (p = path, i = 0; *p && i < _MAX_PATH; ++i) { if ((p[0] & 0xe0) == 0xc0 && p[1] && (p[1] & 0xc0) == 0x80) { nPath[i] = (char)(((p[0] & 0x1f) << 6) | (p[1] & 0x3f)); p += 2; } else if ((p[0] & 0xf0) == 0xe0 && p[1] && (p[1] & 0xc0) == 0x80 && p[2] && (p[2] & 0xc0) == 0x80) { nPath[i] = (char)(((p[1] & 0x3f) << 6) | (p[2] & 0x3f)); p += 3; } else { nPath[i] = p[0]; p += 1; } } nPath[i] = '\0'; return fopen(nPath, mode); } #else return fopen(path, mode); #endif } char *getLine(char *buf, int size, FILE *f) { int c, i; i = 0; while (i < size - 1) { if ((c = fgetc(f)) == EOF) { break; } buf[i++] = (char)c; if (c == '\x0a') { break; } if (c == '\x0d') { c = fgetc(f); if (c == '\x0a' && i < size - 1) { buf[i++] = (char)c; } else if (c != EOF) { ungetc(c, f); } break; } } buf[i] = '\0'; if (i == 0) { return NULL; } return buf; } //------------------------------------------------------------------------ // GDir and GDirEntry //------------------------------------------------------------------------ GDirEntry::GDirEntry(char *dirPath, char *nameA, GBool doStat) { #ifdef VMS char *p; #elif defined(WIN32) int fa; GString *s; #elif defined(ACORN) #else struct stat st; GString *s; #endif name = new GString(nameA); dir = gFalse; if (doStat) { #ifdef VMS if (!strcmp(nameA, "-") || ((p = strrchr(nameA, '.')) && !strncmp(p, ".DIR;", 5))) dir = gTrue; #elif defined(ACORN) #else s = new GString(dirPath); appendToPath(s, nameA); #ifdef WIN32 fa = GetFileAttributes(s->getCString()); dir = (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); #else if (stat(s->getCString(), &st) == 0) dir = S_ISDIR(st.st_mode); #endif delete s; #endif } } GDirEntry::~GDirEntry() { delete name; } GDir::GDir(char *name, GBool doStatA) { path = new GString(name); doStat = doStatA; #if defined(WIN32) GString *tmp; tmp = path->copy(); tmp->append("/*.*"); hnd = FindFirstFile(tmp->getCString(), &ffd); delete tmp; #elif defined(ACORN) #elif defined(MACOS) #else dir = opendir(name); #ifdef VMS needParent = strchr(name, '[') != NULL; #endif #endif } GDir::~GDir() { delete path; #if defined(WIN32) if (hnd) { FindClose(hnd); hnd = NULL; } #elif defined(ACORN) #elif defined(MACOS) #else if (dir) closedir(dir); #endif } GDirEntry *GDir::getNextEntry() { GDirEntry *e; #if defined(WIN32) if (hnd) { e = new GDirEntry(path->getCString(), ffd.cFileName, doStat); if (hnd && !FindNextFile(hnd, &ffd)) { FindClose(hnd); hnd = NULL; } } else { e = NULL; } #elif defined(ACORN) #elif defined(MACOS) #elif defined(VMS) struct dirent *ent; e = NULL; if (dir) { if (needParent) { e = new GDirEntry(path->getCString(), "-", doStat); needParent = gFalse; return e; } ent = readdir(dir); if (ent) { e = new GDirEntry(path->getCString(), ent->d_name, doStat); } } #else struct dirent *ent; e = NULL; if (dir) { ent = (struct dirent *)readdir(dir); if (ent && !strcmp(ent->d_name, ".")) { ent = (struct dirent *)readdir(dir); } if (ent) { e = new GDirEntry(path->getCString(), ent->d_name, doStat); } } #endif return e; } void GDir::rewind() { #ifdef WIN32 GString *tmp; if (hnd) FindClose(hnd); tmp = path->copy(); tmp->append("/*.*"); hnd = FindFirstFile(tmp->getCString(), &ffd); delete tmp; #elif defined(ACORN) #elif defined(MACOS) #else if (dir) rewinddir(dir); #ifdef VMS needParent = strchr(path->getCString(), '[') != NULL; #endif #endif } xpdf-3.03/goo/GString.h0000644000076400007640000001021711622305345014226 0ustar dereknderekn//======================================================================== // // GString.h // // Simple variable-length string type. // // Copyright 1996-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GSTRING_H #define GSTRING_H #include #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include // for LLONG_MAX and ULLONG_MAX #include #include "gtypes.h" class GString { public: // Create an empty string. GString(); // Create a string from a C string. GString(const char *sA); // Create a string from chars at . This string // can contain null characters. GString(const char *sA, int lengthA); // Create a string from chars at in . GString(GString *str, int idx, int lengthA); // Copy a string. GString(GString *str); GString *copy() { return new GString(this); } // Concatenate two strings. GString(GString *str1, GString *str2); // Convert an integer to a string. static GString *fromInt(int x); // Create a formatted string. Similar to printf, but without the // string overflow issues. Formatting elements consist of: // {:[][.]} // where: // - is the argument number (arg 0 is the first argument // following the format string) -- NB: args must be first used in // order; they can be reused in any order // - is the field width -- negative to reverse the alignment; // starting with a leading zero to zero-fill (for integers) // - is the number of digits to the right of the decimal // point (for floating point numbers) // - is one of: // d, x, o, b -- int in decimal, hex, octal, binary // ud, ux, uo, ub -- unsigned int // ld, lx, lo, lb, uld, ulx, ulo, ulb -- long, unsigned long // lld, llx, llo, llb, ulld, ullx, ullo, ullb // -- long long, unsigned long long // f, g -- double // c -- char // s -- string (char *) // t -- GString * // w -- blank space; arg determines width // To get literal curly braces, use {{ or }}. static GString *format(const char *fmt, ...); static GString *formatv(const char *fmt, va_list argList); // Destructor. ~GString(); // Get length. int getLength() { return length; } // Get C string. char *getCString() { return s; } // Get th character. char getChar(int i) { return s[i]; } // Change th character. void setChar(int i, char c) { s[i] = c; } // Clear string to zero length. GString *clear(); // Append a character or string. GString *append(char c); GString *append(GString *str); GString *append(const char *str); GString *append(const char *str, int lengthA); // Append a formatted string. GString *appendf(const char *fmt, ...); GString *appendfv(const char *fmt, va_list argList); // Insert a character or string. GString *insert(int i, char c); GString *insert(int i, GString *str); GString *insert(int i, const char *str); GString *insert(int i, const char *str, int lengthA); // Delete a character or range of characters. GString *del(int i, int n = 1); // Convert string to all-upper/all-lower case. GString *upperCase(); GString *lowerCase(); // Compare two strings: -1:< 0:= +1:> int cmp(GString *str); int cmpN(GString *str, int n); int cmp(const char *sA); int cmpN(const char *sA, int n); private: int length; char *s; void resize(int length1); #ifdef LLONG_MAX static void formatInt(long long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len); #else static void formatInt(long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len); #endif #ifdef ULLONG_MAX static void formatUInt(unsigned long long x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len); #else static void formatUInt(Gulong x, char *buf, int bufSize, GBool zeroFill, int width, int base, char **p, int *len); #endif static void formatDouble(double x, char *buf, int bufSize, int prec, GBool trim, char **p, int *len); }; #endif xpdf-3.03/goo/FixedPoint.h0000644000076400007640000001405211622305345014723 0ustar dereknderekn//======================================================================== // // FixedPoint.h // // Fixed point type, with C++ operators. // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #ifndef FIXEDPOINT_H #define FIXEDPOINT_H #include #if USE_FIXEDPOINT #ifdef USE_GCC_PRAGMAS #pragma interface #endif #include #include #include "gtypes.h" #define fixptShift 16 #define fixptMaskL ((1 << fixptShift) - 1) #define fixptMaskH (~fixptMaskL) typedef long long FixPtInt64; class FixedPoint { public: FixedPoint() { val = 0; } FixedPoint(const FixedPoint &x) { val = x.val; } FixedPoint(double x) { val = (int)(x * (1 << fixptShift) + 0.5); } FixedPoint(int x) { val = x << fixptShift; } FixedPoint(long x) { val = x << fixptShift; } operator float() { return (float) val * ((float)1 / (float)(1 << fixptShift)); } operator double() { return (double) val * (1.0 / (double)(1 << fixptShift)); } operator int() { return val >> fixptShift; } int get16Dot16() { return val; } FixedPoint operator =(FixedPoint x) { val = x.val; return *this; } int operator ==(FixedPoint x) { return val == x.val; } int operator ==(double x) { return *this == (FixedPoint)x; } int operator ==(int x) { return *this == (FixedPoint)x; } int operator ==(long x) { return *this == (FixedPoint)x; } int operator !=(FixedPoint x) { return val != x.val; } int operator !=(double x) { return *this != (FixedPoint)x; } int operator !=(int x) { return *this != (FixedPoint)x; } int operator !=(long x) { return *this != (FixedPoint)x; } int operator <(FixedPoint x) { return val < x.val; } int operator <(double x) { return *this < (FixedPoint)x; } int operator <(int x) { return *this < (FixedPoint)x; } int operator <(long x) { return *this < (FixedPoint)x; } int operator <=(FixedPoint x) { return val <= x.val; } int operator <=(double x) { return *this <= (FixedPoint)x; } int operator <=(int x) { return *this <= (FixedPoint)x; } int operator <=(long x) { return *this <= (FixedPoint)x; } int operator >(FixedPoint x) { return val > x.val; } int operator >(double x) { return *this > (FixedPoint)x; } int operator >(int x) { return *this > (FixedPoint)x; } int operator >(long x) { return *this > (FixedPoint)x; } int operator >=(FixedPoint x) { return val >= x.val; } int operator >=(double x) { return *this >= (FixedPoint)x; } int operator >=(int x) { return *this >= (FixedPoint)x; } int operator >=(long x) { return *this >= (FixedPoint)x; } FixedPoint operator -() { return make(-val); } FixedPoint operator +(FixedPoint x) { return make(val + x.val); } FixedPoint operator +(double x) { return *this + (FixedPoint)x; } FixedPoint operator +(int x) { return *this + (FixedPoint)x; } FixedPoint operator +(long x) { return *this + (FixedPoint)x; } FixedPoint operator +=(FixedPoint x) { val = val + x.val; return *this; } FixedPoint operator +=(double x) { return *this += (FixedPoint)x; } FixedPoint operator +=(int x) { return *this += (FixedPoint)x; } FixedPoint operator +=(long x) { return *this += (FixedPoint)x; } FixedPoint operator -(FixedPoint x) { return make(val - x.val); } FixedPoint operator -(double x) { return *this - (FixedPoint)x; } FixedPoint operator -(int x) { return *this - (FixedPoint)x; } FixedPoint operator -(long x) { return *this - (FixedPoint)x; } FixedPoint operator -=(FixedPoint x) { val = val - x.val; return *this; } FixedPoint operator -=(double x) { return *this -= (FixedPoint)x; } FixedPoint operator -=(int x) { return *this -= (FixedPoint)x; } FixedPoint operator -=(long x) { return *this -= (FixedPoint)x; } FixedPoint operator *(FixedPoint x) { return make(mul(val, x.val)); } FixedPoint operator *(double x) { return *this * (FixedPoint)x; } FixedPoint operator *(int x) { return *this * (FixedPoint)x; } FixedPoint operator *(long x) { return *this * (FixedPoint)x; } FixedPoint operator *=(FixedPoint x) { val = mul(val, x.val); return *this; } FixedPoint operator *=(double x) { return *this *= (FixedPoint)x; } FixedPoint operator *=(int x) { return *this *= (FixedPoint)x; } FixedPoint operator *=(long x) { return *this *= (FixedPoint)x; } FixedPoint operator /(FixedPoint x) { return make(div(val, x.val)); } FixedPoint operator /(double x) { return *this / (FixedPoint)x; } FixedPoint operator /(int x) { return *this / (FixedPoint)x; } FixedPoint operator /(long x) { return *this / (FixedPoint)x; } FixedPoint operator /=(FixedPoint x) { val = div(val, x.val); return *this; } FixedPoint operator /=(double x) { return *this /= (FixedPoint)x; } FixedPoint operator /=(int x) { return *this /= (FixedPoint)x; } FixedPoint operator /=(long x) { return *this /= (FixedPoint)x; } static FixedPoint abs(FixedPoint x) { return make(::abs(x.val)); } static int floor(FixedPoint x) { return x.val >> fixptShift; } static int ceil(FixedPoint x) { return (x.val & fixptMaskL) ? ((x.val >> fixptShift) + 1) : (x.val >> fixptShift); } static int round(FixedPoint x) { return (x.val + (1 << (fixptShift - 1))) >> fixptShift; } // Computes (x+y)/2 avoiding overflow and LSbit accuracy issues. static FixedPoint avg(FixedPoint x, FixedPoint y) { return make((x.val >> 1) + (y.val >> 1) + ((x.val | y.val) & 1)); } static FixedPoint sqrt(FixedPoint x); static FixedPoint pow(FixedPoint x, FixedPoint y); // Compute *result = x/y; return false if there is an underflow or // overflow. static GBool divCheck(FixedPoint x, FixedPoint y, FixedPoint *result); // Compute abs(m11*m22 - m12*m21) >= epsilon, handling the case // where the multiplications overflow. static GBool checkDet(FixedPoint m11, FixedPoint m12, FixedPoint m21, FixedPoint m22, FixedPoint epsilon); private: static FixedPoint make(int valA) { FixedPoint x; x.val = valA; return x; } static int mul(int x, int y); static int div(int x, int y); int val; // fixed point: (n-fixptShift).(fixptShift) }; #endif // USE_FIXEDPOINT #endif xpdf-3.03/goo/parseargs.c0000644000076400007640000000670511622305345014642 0ustar dereknderekn/* * parseargs.h * * Command line argument parser. * * Copyright 1996-2003 Glyph & Cog, LLC */ #include #include #include #include #include #include "parseargs.h" static ArgDesc *findArg(ArgDesc *args, char *arg); static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]); GBool parseArgs(ArgDesc *args, int *argc, char *argv[]) { ArgDesc *arg; int i, j; GBool ok; ok = gTrue; i = 1; while (i < *argc) { if (!strcmp(argv[i], "--")) { --*argc; for (j = i; j < *argc; ++j) argv[j] = argv[j+1]; break; } else if ((arg = findArg(args, argv[i]))) { if (!grabArg(arg, i, argc, argv)) ok = gFalse; } else { ++i; } } return ok; } void printUsage(const char *program, const char *otherArgs, ArgDesc *args) { ArgDesc *arg; char *typ; int w, w1; w = 0; for (arg = args; arg->arg; ++arg) { if ((w1 = (int)strlen(arg->arg)) > w) w = w1; } fprintf(stderr, "Usage: %s [options]", program); if (otherArgs) fprintf(stderr, " %s", otherArgs); fprintf(stderr, "\n"); for (arg = args; arg->arg; ++arg) { fprintf(stderr, " %s", arg->arg); w1 = 9 + w - (int)strlen(arg->arg); switch (arg->kind) { case argInt: case argIntDummy: typ = " "; break; case argFP: case argFPDummy: typ = " "; break; case argString: case argStringDummy: typ = " "; break; case argFlag: case argFlagDummy: default: typ = ""; break; } fprintf(stderr, "%-*s", w1, typ); if (arg->usage) fprintf(stderr, ": %s", arg->usage); fprintf(stderr, "\n"); } } static ArgDesc *findArg(ArgDesc *args, char *arg) { ArgDesc *p; for (p = args; p->arg; ++p) { if (p->kind < argFlagDummy && !strcmp(p->arg, arg)) return p; } return NULL; } static GBool grabArg(ArgDesc *arg, int i, int *argc, char *argv[]) { int n; int j; GBool ok; ok = gTrue; n = 0; switch (arg->kind) { case argFlag: *(GBool *)arg->val = gTrue; n = 1; break; case argInt: if (i + 1 < *argc && isInt(argv[i+1])) { *(int *)arg->val = atoi(argv[i+1]); n = 2; } else { ok = gFalse; n = 1; } break; case argFP: if (i + 1 < *argc && isFP(argv[i+1])) { *(double *)arg->val = atof(argv[i+1]); n = 2; } else { ok = gFalse; n = 1; } break; case argString: if (i + 1 < *argc) { strncpy((char *)arg->val, argv[i+1], arg->size - 1); ((char *)arg->val)[arg->size - 1] = '\0'; n = 2; } else { ok = gFalse; n = 1; } break; default: fprintf(stderr, "Internal error in arg table\n"); n = 1; break; } if (n > 0) { *argc -= n; for (j = i; j < *argc; ++j) argv[j] = argv[j+n]; } return ok; } GBool isInt(char *s) { if (*s == '-' || *s == '+') ++s; while (isdigit(*s & 0xff)) ++s; if (*s) return gFalse; return gTrue; } GBool isFP(char *s) { int n; if (*s == '-' || *s == '+') ++s; n = 0; while (isdigit(*s & 0xff)) { ++s; ++n; } if (*s == '.') ++s; while (isdigit(*s & 0xff)) { ++s; ++n; } if (n > 0 && (*s == 'e' || *s == 'E')) { ++s; if (*s == '-' || *s == '+') ++s; n = 0; if (!isdigit(*s & 0xff)) return gFalse; do { ++s; } while (isdigit(*s & 0xff)); } if (*s) return gFalse; return gTrue; } xpdf-3.03/goo/FixedPoint.cc0000644000076400007640000000524311622305345015063 0ustar dereknderekn//======================================================================== // // FixedPoint.cc // // Fixed point type, with C++ operators. // // Copyright 2004 Glyph & Cog, LLC // //======================================================================== #include #if USE_FIXEDPOINT #ifdef USE_GCC_PRAGMAS #pragma implementation #endif #include "FixedPoint.h" #define ln2 ((FixedPoint)0.69314718) FixedPoint FixedPoint::sqrt(FixedPoint x) { FixedPoint y0, y1, z; if (x.val <= 0) { y1.val = 0; } else { y1.val = x.val == 1 ? 2 : x.val >> 1; do { y0.val = y1.val; z = x / y0; y1.val = (y0.val + z.val) >> 1; } while (::abs(y0.val - y1.val) > 1); } return y1; } FixedPoint FixedPoint::pow(FixedPoint x, FixedPoint y) { FixedPoint t, t2, lnx0, lnx, z0, z; int d, n, i; if (y.val <= 0) { z.val = 0; } else { // y * ln(x) t = (x - 1) / (x + 1); t2 = t * t; d = 1; lnx = 0; do { lnx0 = lnx; lnx += t / d; t *= t2; d += 2; } while (::abs(lnx.val - lnx0.val) > 2); lnx.val <<= 1; t = y * lnx; // exp(y * ln(x)) n = floor(t / ln2); t -= ln2 * n; t2 = t; d = 1; i = 1; z = 1; do { z0 = z; z += t2 / d; t2 *= t; ++i; d *= i; } while (::abs(z.val - z0.val) > 2 && d < (1 << fixptShift)); if (n >= 0) { z.val <<= n; } else if (n < 0) { z.val >>= -n; } } return z; } int FixedPoint::mul(int x, int y) { FixPtInt64 z; z = ((FixPtInt64)x * y) >> fixptShift; if (z > 0x7fffffffLL) { return 0x7fffffff; } else if (z < -0x80000000LL) { return 0x80000000; } else { return (int)z; } } int FixedPoint::div(int x, int y) { FixPtInt64 z; z = ((FixPtInt64)x << fixptShift) / y; if (z > 0x7fffffffLL) { return 0x7fffffff; } else if (z < -0x80000000LL) { return 0x80000000; } else { return (int)z; } } GBool FixedPoint::divCheck(FixedPoint x, FixedPoint y, FixedPoint *result) { FixPtInt64 z; z = ((FixPtInt64)x.val << fixptShift) / y.val; if ((z == 0 && x != 0) || z >= ((FixPtInt64)1 << 31) || z < -((FixPtInt64)1 << 31)) { return gFalse; } result->val = z; return gTrue; } GBool FixedPoint::checkDet(FixedPoint m11, FixedPoint m12, FixedPoint m21, FixedPoint m22, FixedPoint epsilon) { FixPtInt64 det, e; det = (FixPtInt64)m11.val * (FixPtInt64)m22.val - (FixPtInt64)m12.val * (FixPtInt64)m21.val; e = (FixPtInt64)epsilon.val << fixptShift; // NB: this comparison has to be >= not > because epsilon can be // truncated to zero as a fixed point value. return det >= e || det <= -e; } #endif // USE_FIXEDPOINT xpdf-3.03/goo/Makefile.in0000644000076400007640000000310211622305345014540 0ustar dereknderekn#======================================================================== # # Goo library Makefile # # Copyright 1996-2003 Glyph & Cog, LLC # #======================================================================== SHELL = /bin/sh srcdir = @srcdir@ VPATH = @srcdir@ CFLAGS = @CFLAGS@ @DEFS@ -I.. -I$(srcdir) CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(srcdir) CC = @CC@ CXX = @CXX@ AR = @AR@ RANLIB = @RANLIB@ LIBPREFIX = @LIBPREFIX@ #------------------------------------------------------------------------ .SUFFIXES: .cc .cc.o: $(CXX) $(CXXFLAGS) -c $< #------------------------------------------------------------------------ CXX_SRC = \ $(srcdir)/GHash.cc \ $(srcdir)/GList.cc \ $(srcdir)/GString.cc \ $(srcdir)/gmem.cc \ $(srcdir)/gmempp.cc \ $(srcdir)/gfile.cc \ $(srcdir)/FixedPoint.cc C_SRC = \ $(srcdir)/parseargs.c #------------------------------------------------------------------------ all: $(LIBPREFIX)Goo.a #------------------------------------------------------------------------ GOO_CXX_OBJS = GHash.o GList.o GString.o gmem.o gmempp.o gfile.o FixedPoint.o GOO_C_OBJS = parseargs.o GOO_OBJS = $(GOO_CXX_OBJS) $(GOO_C_OBJS) $(LIBPREFIX)Goo.a: $(GOO_OBJS) rm -f $(LIBPREFIX)Goo.a $(AR) $(LIBPREFIX)Goo.a $(GOO_OBJS) $(RANLIB) $(LIBPREFIX)Goo.a #------------------------------------------------------------------------ clean: rm -f $(GOO_OBJS) $(LIBPREFIX)Goo.a #------------------------------------------------------------------------ depend: $(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep $(CC) $(CFLAGS) -MM $(C_SRC) >>Makefile.dep include Makefile.dep xpdf-3.03/goo/GMutex.h0000644000076400007640000000172711622305345014070 0ustar dereknderekn//======================================================================== // // GMutex.h // // Portable mutex macros. // // Copyright 2002-2003 Glyph & Cog, LLC // //======================================================================== #ifndef GMUTEX_H #define GMUTEX_H // Usage: // // GMutex m; // gInitMutex(&m); // ... // gLockMutex(&m); // ... critical section ... // gUnlockMutex(&m); // ... // gDestroyMutex(&m); #ifdef WIN32 #include typedef CRITICAL_SECTION GMutex; #define gInitMutex(m) InitializeCriticalSection(m) #define gDestroyMutex(m) DeleteCriticalSection(m) #define gLockMutex(m) EnterCriticalSection(m) #define gUnlockMutex(m) LeaveCriticalSection(m) #else // assume pthreads #include typedef pthread_mutex_t GMutex; #define gInitMutex(m) pthread_mutex_init(m, NULL) #define gDestroyMutex(m) pthread_mutex_destroy(m) #define gLockMutex(m) pthread_mutex_lock(m) #define gUnlockMutex(m) pthread_mutex_unlock(m) #endif #endif xpdf-3.03/goo/gtypes.h0000644000076400007640000000106211622305345014162 0ustar dereknderekn/* * gtypes.h * * Some useful simple types. * * Copyright 1996-2003 Glyph & Cog, LLC */ #ifndef GTYPES_H #define GTYPES_H /* * These have stupid names to avoid conflicts with some (but not all) * C++ compilers which define them. */ typedef int GBool; #define gTrue 1 #define gFalse 0 /* * These have stupid names to avoid conflicts with , * which on various systems defines some random subset of these. */ typedef unsigned char Guchar; typedef unsigned short Gushort; typedef unsigned int Guint; typedef unsigned long Gulong; #endif xpdf-3.03/goo/vms_unlink.c0000644000076400007640000000073411622305345015034 0ustar dereknderekn/* * vms_unlink.c * * A UNIX-style unlink() function for VMS. * * Thanks to Patrick Moreau (pmoreau@cena.dgac.fr). */ #include #include #include int unlink(char *filename) { static struct dsc$descriptor_s file_desc; file_desc.dsc$w_length = strlen(filename); file_desc.dsc$b_dtype = DSC$K_DTYPE_T; file_desc.dsc$b_class = DSC$K_CLASS_S; file_desc.dsc$a_pointer= filename; return (lib$delete_file(&file_desc)); }