diff options
Diffstat (limited to 'Build/source/libs/xpdf')
56 files changed, 4527 insertions, 1276 deletions
diff --git a/Build/source/libs/xpdf/ANNOUNCE b/Build/source/libs/xpdf/ANNOUNCE index 3f12a2602f8..1184040894f 100644 --- a/Build/source/libs/xpdf/ANNOUNCE +++ b/Build/source/libs/xpdf/ANNOUNCE @@ -1,4 +1,4 @@ -Subject: ANNOUNCE: Xpdf 3.01 - a PDF viewer for X +Subject: ANNOUNCE: Xpdf 3.02 - a PDF viewer for X Glyph & Cog, LLC is pleased to announce a new version of Xpdf, the @@ -11,12 +11,11 @@ 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 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. +* Anti-aliased vector graphics, including stroke adjustment. +* Support for PDF 1.6 and PDF 1.7, including AES decryption and + OpenType fonts. +* User-configurable key/mouse bindings. +* Improved full-screen mode, with the ability to toggle on the fly. See the `CHANGES' file for a complete list of changes. diff --git a/Build/source/libs/xpdf/CHANGES b/Build/source/libs/xpdf/CHANGES index 360dd25a105..0378f0da537 100644 --- a/Build/source/libs/xpdf/CHANGES +++ b/Build/source/libs/xpdf/CHANGES @@ -1577,7 +1577,8 @@ Minor changes to GlobalParams.h and JPXStream.h because some compilers Xpdf now complains about a negative page number. Changed GString::cmp and GString::cmpN to correctly handle '\0' chars in the middle of strings. -Corrected the handling of the 'extend' parameters in radial shadings. +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. @@ -1626,3 +1627,136 @@ When converting a Type 1C glyph to a Type 1 glyph, insert closepath 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. diff --git a/Build/source/libs/xpdf/INSTALL b/Build/source/libs/xpdf/INSTALL index 10036518c6f..6c6db871129 100644 --- a/Build/source/libs/xpdf/INSTALL +++ b/Build/source/libs/xpdf/INSTALL @@ -1,11 +1,11 @@ Xpdf ==== -version 3.01 -2005-aug-17 +version 3.02 +2007-feb-27 The Xpdf software and documentation are -copyright 1996-2005 Glyph & Cog, LLC. +copyright 1996-2007 Glyph & Cog, LLC. Email: derekn@foolabs.com WWW: http://www.foolabs.com/xpdf/ diff --git a/Build/source/libs/xpdf/README b/Build/source/libs/xpdf/README index 5fb5b104c31..71fd62e319d 100644 --- a/Build/source/libs/xpdf/README +++ b/Build/source/libs/xpdf/README @@ -1,17 +1,17 @@ Xpdf ==== -version 3.01 -2005-aug-17 +version 3.02 +2007-feb-27 The Xpdf software and documentation are -copyright 1996-2005 Glyph & Cog, LLC. +copyright 1996-2007 Glyph & Cog, LLC. Email: derekn@foolabs.com WWW: http://www.foolabs.com/xpdf/ The PDF data structures, operators, and specification are -copyright 1985-2004 Adobe Systems Inc. +copyright 1985-2006 Adobe Systems Inc. What is Xpdf? @@ -204,10 +204,15 @@ pdftex project: References ---------- -Adobe Systems Inc., _PDF Reference: Adobe Portable Document Format -Version 1.6_. -http://partners.adobe.com/public/developer/pdf/index_reference.html -[The manual for PDF version 1.6.] +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. @@ -262,6 +267,10 @@ 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 @@ -271,7 +280,7 @@ 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. +Version 1.0". RFC 2083. [PDF uses the PNG filter algorithms.] CCITT, "Information Technology - Digital Compression and Coding of @@ -296,6 +305,15 @@ 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 @@ -333,6 +351,10 @@ 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. @@ -342,10 +364,11 @@ 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).] -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.] +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 @@ -359,6 +382,11 @@ http://www.inforamp.net/~poynton/ColorFAQ.html 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.] diff --git a/Build/source/libs/xpdf/aconf-win32.h b/Build/source/libs/xpdf/aconf-win32.h index 60509334391..0bdc7636623 100644 --- a/Build/source/libs/xpdf/aconf-win32.h +++ b/Build/source/libs/xpdf/aconf-win32.h @@ -7,6 +7,8 @@ #ifndef ACONF_H #define ACONF_H +#include <aconf2.h> + /* * Use A4 paper size instead of Letter for PostScript output. */ @@ -28,6 +30,21 @@ #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 @@ -50,8 +67,14 @@ #undef HAVE_BSTRING_H #undef HAVE_POPEN #undef HAVE_MKSTEMP +#undef HAVE_MKSTEMPS #undef SELECT_TAKES_INT +#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. @@ -79,4 +102,19 @@ */ #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 diff --git a/Build/source/libs/xpdf/aconf.h.in b/Build/source/libs/xpdf/aconf.h.in index b7928fb3fc2..b6c63518f53 100644 --- a/Build/source/libs/xpdf/aconf.h.in +++ b/Build/source/libs/xpdf/aconf.h.in @@ -30,11 +30,21 @@ #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 @@ -87,4 +97,19 @@ */ #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 diff --git a/Build/source/libs/xpdf/dj_make.bat b/Build/source/libs/xpdf/dj_make.bat index 37f360359df..d01b7928c63 100644 --- a/Build/source/libs/xpdf/dj_make.bat +++ b/Build/source/libs/xpdf/dj_make.bat @@ -1,5 +1,5 @@ set CC=gcc
-set CFLAGS=-g -O2 -I.. -I..\goo
+set CFLAGS=-g -O2 -I.. -I..\fofi -I..\goo
set CXX=gpp
set CXXFLAGS=%CFLAGS%
set LIBPROG=ar
@@ -10,9 +10,9 @@ 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 gmem.c
%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
@@ -59,6 +59,7 @@ del *.o %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
@@ -67,16 +68,14 @@ del *.o del libxpdf.a
%LIBPROG% -rc libxpdf.a *.o
-%CXX% %CXXFLAGS% -o pdftops.exe pdftops.cc libxpdf.a ..\goo\libGoo.a
+%CXX% %CXXFLAGS% -o pdftops.exe pdftops.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a
-%CXX% %CXXFLAGS% -o pdftotext.exe pdftotext.cc libxpdf.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 ..\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 ..\goo\libGoo.a
+%CXX% %CXXFLAGS% -o pdffonts.exe pdffonts.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a
-%CXX% %CXXFLAGS% -o pdfimages.exe pdfimages.cc libxpdf.a ..\goo\libGoo.a
-
-%CXX% %CXXFLAGS% -o pdftoppm.exe pdftoppm.cc libxpdf.a ..\goo\libGoo.a
+%CXX% %CXXFLAGS% -o pdfimages.exe pdfimages.cc libxpdf.a ..\fofi\libfofi.a ..\goo\libGoo.a
cd ..
diff --git a/Build/source/libs/xpdf/fofi/FoFiTrueType.cc b/Build/source/libs/xpdf/fofi/FoFiTrueType.cc index 46b61ec3979..f8a1aa3478e 100644 --- a/Build/source/libs/xpdf/fofi/FoFiTrueType.cc +++ b/Build/source/libs/xpdf/fofi/FoFiTrueType.cc @@ -18,6 +18,7 @@ #include "gmem.h" #include "GString.h" #include "GHash.h" +#include "FoFiType1C.h" #include "FoFiTrueType.h" // @@ -108,8 +109,11 @@ struct TrueTypeLoca { #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 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) { @@ -391,6 +395,28 @@ int FoFiTrueType::mapNameToGID(char *name) { return nameToGID->lookupInt(name); } +Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) { + FoFiType1C *ff; + Gushort *map; + int i; + + *nCIDs = 0; + if (!openTypeCFF) { + return NULL; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return NULL; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return NULL; + } + map = ff->getCIDToGIDMap(nCIDs); + delete ff; + return map; +} + int FoFiTrueType::getEmbeddingRights() { int i, fsType; GBool ok; @@ -419,13 +445,19 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding, Gushort *codeToGID, FoFiOutputFunc outputFunc, void *outputStream) { - char buf[512]; + GString *buf; GBool ok; + if (openTypeCFF) { + return; + } + // write the header ok = gTrue; - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -434,9 +466,10 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding, (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 42 def\n", 17); (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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 @@ -448,20 +481,47 @@ void FoFiTrueType::convertToType42(char *psName, char **encoding, (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); } +void FoFiTrueType::convertToType1(char *psName, char **newEncoding, + GBool ascii, FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream); + delete ff; +} + void FoFiTrueType::convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { - char buf[512]; + GString *buf; Gushort cid; GBool ok; int i, j, k; + if (openTypeCFF) { + return; + } + // write the header ok = gTrue; - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -477,8 +537,9 @@ void FoFiTrueType::convertToCIDType2(char *psName, (*outputFunc)(outputStream, " end def\n", 10); (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); if (cidMap) { - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { @@ -487,8 +548,10 @@ void FoFiTrueType::convertToCIDType2(char *psName, (*outputFunc)(outputStream, " ", 2); for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { cid = cidMap[i+j+k]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } (*outputFunc)(outputStream, "\n", 1); } @@ -502,8 +565,10 @@ void FoFiTrueType::convertToCIDType2(char *psName, (*outputFunc)(outputStream, " ", 2); for (j = 0; j < 16 && i+j < nCIDs; ++j) { cid = cidMap[i+j]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("{0:02x}{1:02x}", + (cid >> 8) & 0xff, cid & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } (*outputFunc)(outputStream, "\n", 1); } @@ -511,27 +576,34 @@ void FoFiTrueType::convertToCIDType2(char *psName, } } else { // direct mapping - just fill the string(s) with s[i]=i - sprintf(buf, "/CIDCount %d def\n", nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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; - sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" - " 255 and put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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 { - sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, @@ -541,9 +613,10 @@ void FoFiTrueType::convertToCIDType2(char *psName, } } (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -559,14 +632,39 @@ void FoFiTrueType::convertToCIDType2(char *psName, 56); } +void FoFiTrueType::convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToCIDType0(psName, outputFunc, outputStream); + delete ff; +} + void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream) { - char buf[512]; + GString *buf; GString *sfntsName; int n, i, j; + if (openTypeCFF) { + return; + } + // write the Type 42 sfnts array sfntsName = (new GString(psName))->append("_sfnts"); cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics); @@ -578,28 +676,33 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, (*outputFunc)(outputStream, "10 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, strlen(psName)); (*outputFunc)(outputStream, "_sfnts def\n", 11); (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, @@ -616,21 +719,44 @@ void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs, (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); (*outputFunc)(outputStream, "/Encoding [\n", 12); for (i = 0; i < n; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, + FoFiOutputFunc outputFunc, + void *outputStream) { + FoFiType1C *ff; + int i; + + if (!openTypeCFF) { + return; + } + i = seekTable("CFF "); + if (!checkRegion(tables[i].offset, tables[i].len)) { + return; + } + if (!(ff = FoFiType1C::make((char *)file + tables[i].offset, + tables[i].len))) { + return; + } + ff->convertToType0(psName, outputFunc, outputStream); + delete ff; +} + void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, void *outputStream, char *name, Gushort *codeToGID) { @@ -672,12 +798,50 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 0, 0, 0, 0, // min Type 1 memory 0, 0, 0, 0 // max Type 1 memory }; - GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen; + static char os2Tab[86] = { + 0, 1, // version + 0, 1, // xAvgCharWidth + 0, 0, // usWeightClass + 0, 0, // 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 + 0, 0, // usWinAscent + 0, 0, // usWinDescent + 0, 0, 0, 0, // ulCodePageRange1 + 0, 0, 0, 0 // ulCodePageRange2 + }; + GBool missingCmap, missingName, missingPost, missingOS2; + GBool unsortedLoca, badCmapLen, abbrevHMTX; int nZeroLengthTables; + int nHMetrics, advWidth, lsb; TrueTypeLoca *locaTable; TrueTypeTable *newTables; - char *newNameTab, *newCmapTab; + 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]; @@ -685,10 +849,20 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 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)); @@ -705,6 +879,19 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 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; } @@ -732,9 +919,17 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } } + // 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 && !unsortedLoca && - !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) { + if (!missingCmap && !missingName && !missingPost && !missingOS2 && + !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 && + !name && !codeToGID) { (*outputFunc)(outputStream, (char *)file, len); goto done1; } @@ -892,6 +1087,44 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 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 @@ -901,7 +1134,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, // - (re)compute table checksums nNewTables = nTables - nZeroLengthTables + (missingCmap ? 1 : 0) + (missingName ? 1 : 0) + - (missingPost ? 1 : 0); + (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0); newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable)); j = 0; for (i = 0; i < nTables; ++i) { @@ -932,6 +1165,14 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 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; } @@ -969,6 +1210,13 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, 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; + } qsort(newTables, nNewTables, sizeof(TrueTypeTable), &cmpTrueTypeTableTag); pos = 12 + nNewTables * 16; @@ -1055,6 +1303,12 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, (*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) { @@ -1102,6 +1356,8 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc, } } + gfree(newHMTXTab); + gfree(newHHEATab); gfree(newCmapTab); gfree(newNameTab); gfree(tableDir); @@ -1114,7 +1370,7 @@ void FoFiTrueType::cvtEncoding(char **encoding, FoFiOutputFunc outputFunc, void *outputStream) { char *name; - char buf[64]; + GString *buf; int i; (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); @@ -1123,15 +1379,17 @@ void FoFiTrueType::cvtEncoding(char **encoding, if (!(name = encoding[i])) { name = ".notdef"; } - sprintf(buf, "dup %d /", i); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("dup {0:d} /", i); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; (*outputFunc)(outputStream, name, strlen(name)); (*outputFunc)(outputStream, " put\n", 5); } } else { for (i = 0; i < 256; ++i) { - sprintf(buf, "dup %d /c%02x put\n", i, i); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -1142,7 +1400,8 @@ void FoFiTrueType::cvtCharStrings(char **encoding, FoFiOutputFunc outputFunc, void *outputStream) { char *name; - char buf[64], buf2[16]; + GString *buf; + char buf2[16]; int i, k; // always define '.notdef' @@ -1177,8 +1436,9 @@ void FoFiTrueType::cvtCharStrings(char **encoding, if (k > 0 && k < nGlyphs) { (*outputFunc)(outputStream, "/", 1); (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, " %d def\n", k); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format(" {0:d} def\n", k); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } } } @@ -1481,14 +1741,15 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc, void FoFiTrueType::dumpString(Guchar *s, int length, FoFiOutputFunc outputFunc, void *outputStream) { - char buf[64]; + 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) { - sprintf(buf, "%02X", s[i+j] & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -1537,7 +1798,7 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) { void FoFiTrueType::parse() { Guint topTag; - int pos, i, j; + int pos, ver, i, j; parsedOk = gTrue; @@ -1555,6 +1816,13 @@ void FoFiTrueType::parse() { 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) { @@ -1581,10 +1849,11 @@ void FoFiTrueType::parse() { // the Type 42 spec if (seekTable("head") < 0 || seekTable("hhea") < 0 || - seekTable("loca") < 0 || seekTable("maxp") < 0 || - seekTable("glyf") < 0 || - seekTable("hmtx") < 0) { + seekTable("hmtx") < 0 || + (!openTypeCFF && seekTable("loca") < 0) || + (!openTypeCFF && seekTable("glyf") < 0) || + (openTypeCFF && seekTable("CFF ") < 0)) { parsedOk = gFalse; return; } @@ -1633,23 +1902,28 @@ void FoFiTrueType::parse() { // make sure the loca table is sane (correct length and entries are // in bounds) - i = seekTable("loca"); - if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) { - parsedOk = gFalse; - return; - } - 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) { + 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; } - } - if (!parsedOk) { - return; } // read the post table diff --git a/Build/source/libs/xpdf/fofi/FoFiTrueType.h b/Build/source/libs/xpdf/fofi/FoFiTrueType.h index f7b09d6c0ab..cf06ae78a9e 100644 --- a/Build/source/libs/xpdf/fofi/FoFiTrueType.h +++ b/Build/source/libs/xpdf/fofi/FoFiTrueType.h @@ -38,6 +38,10 @@ public: 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(); @@ -59,6 +63,11 @@ public: // 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 *<nCIDs>. This is only useful for CID fonts. (Only + // useful for OpenType CFF fonts.) + Gushort *getCIDToGIDMap(int *nCIDs); + // Returns the least restrictive embedding licensing right (as // defined by the TrueType spec): // * 4: OS/2 table is missing or invalid @@ -74,33 +83,57 @@ public: // <encoding> array specifies the mapping from char codes to names. // If <encoding> is NULL, the encoding is unknown or undefined. The // <codeToGID> array specifies the mapping from char codes to GIDs. + // (Not useful for OpenType CFF fonts.) void convertToType42(char *psName, char **encoding, Gushort *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 <newEncoding> is + // not NULL, it will be used in place of the encoding in the Type 1C + // font. If <ascii> is true the eexec section will be hex-encoded, + // otherwise it will be left as binary data. If <psName> is + // non-NULL, it will be used as the PostScript font name. (Only + // useful for OpenType CFF fonts.) + void convertToType1(char *psName, char **newEncoding, GBool ascii, + FoFiOutputFunc outputFunc, void *outputStream); + // Convert to a Type 2 CIDFont, suitable for embedding in a // PostScript file. <psName> will be used as the PostScript font // name (so we don't need to depend on the 'name' table in the // font). The <cidMap> array maps CIDs to GIDs; it has <nCIDs> - // entries. + // entries. (Not useful for OpenType CFF fonts.) void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs, GBool needVerticalMetrics, FoFiOutputFunc outputFunc, void *outputStream); + // Convert to a Type 0 CIDFont, suitable for embedding in a + // PostScript file. <psName> will be used as the PostScript font + // name. (Only useful for OpenType CFF fonts.) + void convertToCIDType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + // Convert to a Type 0 (but non-CID) composite font, suitable for // embedding in a PostScript file. <psName> will be used as the // PostScript font name (so we don't need to depend on the 'name' // table in the font). The <cidMap> array maps CIDs to GIDs; it has - // <nCIDs> entries. + // <nCIDs> entries. (Not useful for OpenType CFF fonts.) void convertToType0(char *psName, Gushort *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. <psName> will be used as the + // PostScript font name. (Only useful for OpenType CFF fonts.) + void convertToType0(char *psName, + FoFiOutputFunc outputFunc, void *outputStream); + // Write a clean TTF file, filling in missing tables and correcting // various other errors. If <name> is non-NULL, the font is renamed // to <name>. If <codeToGID> is non-NULL, the font is re-encoded, // using a Windows Unicode cmap. If <name> is NULL and the font is - // complete and correct, it will be written unmodified. + // complete and correct, it will be written unmodified. (Not useful + // for OpenType CFF fonts.) void writeTTF(FoFiOutputFunc outputFunc, void *outputStream, char *name = NULL, Gushort *codeToGID = NULL); @@ -133,6 +166,7 @@ private: int locaFmt; int bbox[4]; GHash *nameToGID; + GBool openTypeCFF; GBool parsedOk; }; diff --git a/Build/source/libs/xpdf/fofi/FoFiType1.cc b/Build/source/libs/xpdf/fofi/FoFiType1.cc index 256639c1203..efad5ee4eb7 100644 --- a/Build/source/libs/xpdf/fofi/FoFiType1.cc +++ b/Build/source/libs/xpdf/fofi/FoFiType1.cc @@ -75,7 +75,7 @@ char **FoFiType1::getEncoding() { void FoFiType1::writeEncoded(char **newEncoding, FoFiOutputFunc outputFunc, void *outputStream) { char buf[512]; - char *line; + char *line, *line2, *p; int i; // copy everything up to the encoding @@ -101,19 +101,57 @@ void FoFiType1::writeEncoded(char **newEncoding, } (*outputFunc)(outputStream, "readonly def\n", 13); - // copy everything after the encoding + // find the end of the encoding data + //~ this ought to parse PostScript tokens if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { line = getNextLine(line); } else { - for (line = getNextLine(line); - line && strncmp(line, "readonly def", 12); - line = getNextLine(line)) ; - if (line) { - line = getNextLine(line); + // 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) { - (*outputFunc)(outputStream, line, ((char *)file + len) - line); + for (line2 = line, i = 0; + i < 20 && line2 && strncmp(line2, "/Encoding", 9); + line2 = getNextLine(line2), ++i) ; + if (i < 20 && line2) { + (*outputFunc)(outputStream, line, 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, ((char *)file + len) - line); + } } } @@ -178,8 +216,15 @@ void FoFiType1::parse() { if (*p2) { c = *p2; *p2 = '\0'; - if ((code = atoi(p)) < 256) { - *p2 = c; + code = atoi(p); + *p2 = c; + if (code == 8 && *p2 == '#') { + code = 0; + for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) { + code = code * 8 + (*p2 - '0'); + } + } + if (code < 256) { for (p = p2; *p == ' ' || *p == '\t'; ++p) ; if (*p == '/') { ++p; diff --git a/Build/source/libs/xpdf/fofi/FoFiType1C.cc b/Build/source/libs/xpdf/fofi/FoFiType1C.cc index 499414bea2a..3b28f3210c8 100644 --- a/Build/source/libs/xpdf/fofi/FoFiType1C.cc +++ b/Build/source/libs/xpdf/fofi/FoFiType1C.cc @@ -129,24 +129,33 @@ Gushort *FoFiType1C::getCIDToGIDMap(int *nCIDs) { return map; } -void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, +void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream) { + int psNameLen; Type1CEexecBuf eb; Type1CIndex subrIdx; Type1CIndexVal val; - char buf[512]; + GString *buf; + char buf2[256]; char **enc; GBool ok; int i; + if (psName) { + psNameLen = 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, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, psName, psNameLen); if (topDict.versionSID != 0) { - getString(topDict.versionSID, buf, &ok); - (*outputFunc)(outputStream, buf, strlen(buf)); + getString(topDict.versionSID, buf2, &ok); + (*outputFunc)(outputStream, buf2, strlen(buf2)); } (*outputFunc)(outputStream, "\n", 1); // the dictionary needs room for 12 entries: the following 9, plus @@ -156,37 +165,37 @@ void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); if (topDict.versionSID != 0) { (*outputFunc)(outputStream, "/version (", 10); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.noticeSID != 0) { - getString(topDict.noticeSID, buf, &ok); + getString(topDict.noticeSID, buf2, &ok); (*outputFunc)(outputStream, "/Notice (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.copyrightSID != 0) { - getString(topDict.copyrightSID, buf, &ok); + getString(topDict.copyrightSID, buf2, &ok); (*outputFunc)(outputStream, "/Copyright (", 12); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.fullNameSID != 0) { - getString(topDict.fullNameSID, buf, &ok); + getString(topDict.fullNameSID, buf2, &ok); (*outputFunc)(outputStream, "/FullName (", 11); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.familyNameSID != 0) { - getString(topDict.familyNameSID, buf, &ok); + getString(topDict.familyNameSID, buf2, &ok); (*outputFunc)(outputStream, "/FamilyName (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.weightSID != 0) { - getString(topDict.weightSID, buf, &ok); + getString(topDict.weightSID, buf2, &ok); (*outputFunc)(outputStream, "/Weight (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") readonly def\n", 15); } if (topDict.isFixedPitch) { @@ -194,32 +203,43 @@ void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, } else { (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); } - sprintf(buf, "/ItalicAngle %g def\n", topDict.italicAngle); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlinePosition %g def\n", topDict.underlinePosition); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlineThickness %g def\n", topDict.underlineThickness); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, name->getCString(), name->getLength()); + (*outputFunc)(outputStream, psName, psNameLen); (*outputFunc)(outputStream, " def\n", 5); - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], topDict.fontMatrix[2], - topDict.fontMatrix[3], topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/UniqueID %d def\n", topDict.uniqueID); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/UniqueID {0:d} def\n", topDict.uniqueID); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } // write the encoding @@ -233,8 +253,9 @@ void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, enc = newEncoding ? newEncoding : encoding; for (i = 0; i < 256; ++i) { if (enc[i]) { - sprintf(buf, "dup %d /%s put\n", i, enc[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -261,89 +282,112 @@ void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, if (privateDicts[0].nBlueValues) { eexecWrite(&eb, "/BlueValues ["); for (i = 0; i < privateDicts[0].nBlueValues; ++i) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].blueValues[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].otherBlues[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", i > 0 ? " " : "", privateDicts[0].familyBlues[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", i > 0 ? " " : "", - privateDicts[0].familyOtherBlues[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[0].blueScale); - eexecWrite(&eb, buf); + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[0].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[0].blueShift); - eexecWrite(&eb, buf); + buf = GString::format("/BlueShift {0:d} def\n", privateDicts[0].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[0].blueFuzz); - eexecWrite(&eb, buf); + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[0].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[0].stdHW); - eexecWrite(&eb, buf); + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[0].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[0].stdVW); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapH[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%g", i > 0 ? " " : "", privateDicts[0].stemSnapV[i]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[0].forceBold ? "true" : "false"); - eexecWrite(&eb, buf); + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[0].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].forceBoldThreshold != 0) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[0].forceBoldThreshold); - eexecWrite(&eb, buf); + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[0].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[0].languageGroup); - eexecWrite(&eb, buf); + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[0].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[0].expansionFactor != 0.06) { - sprintf(buf, "/ExpansionFactor %g def\n", privateDicts[0].expansionFactor); - eexecWrite(&eb, buf); + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[0].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; } // set up subroutines @@ -354,15 +398,17 @@ void FoFiType1C::convertToType1(char **newEncoding, GBool ascii, } // write the CharStrings - sprintf(buf, "2 index /CharStrings %d dict dup begin\n", nGlyphs); - eexecWrite(&eb, buf); + 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], buf, &ok); + getString(charset[i], buf2, &ok); if (ok) { - eexecCvtGlyph(&eb, buf, val.pos, val.len, &subrIdx, &privateDicts[0]); + eexecCvtGlyph(&eb, buf2, val.pos, val.len, &subrIdx, &privateDicts[0]); } } } @@ -392,7 +438,8 @@ void FoFiType1C::convertToCIDType0(char *psName, Type1CIndex subrIdx; Type1CIndexVal val; int nCIDs, gdBytes; - char buf[512], buf2[512]; + GString *buf; + char buf2[256]; GBool ok; int gid, offset, n, i, j, k; @@ -456,169 +503,204 @@ void FoFiType1C::convertToCIDType0(char *psName, (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); if (topDict.registrySID > 0 && topDict.orderingSID > 0) { ok = gTrue; - getString(topDict.registrySID, buf, &ok); + getString(topDict.registrySID, buf2, &ok); if (ok) { (*outputFunc)(outputStream, " /Registry (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") def\n", 6); } ok = gTrue; - getString(topDict.orderingSID, buf, &ok); + getString(topDict.orderingSID, buf2, &ok); if (ok) { (*outputFunc)(outputStream, " /Ordering (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); + (*outputFunc)(outputStream, buf2, strlen(buf2)); (*outputFunc)(outputStream, ") def\n", 6); } } else { (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); } - sprintf(buf, " /Supplement %d def\n", topDict.supplement); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); } - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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 - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/CIDCount {0:d} def\n", nCIDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); - sprintf(buf, "/GDBytes %d def\n", gdBytes); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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 - sprintf(buf, "/FDArray %d array\n", nFDs); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/FDArray {0:d} array\n", nFDs); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; for (i = 0; i < nFDs; ++i) { - sprintf(buf, "dup %d 10 dict begin\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] 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, strlen(buf)); + 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); } - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].blueValues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].otherBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%d", j > 0 ? " " : "", privateDicts[i].familyBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%d", j > 0 ? " " : "", - privateDicts[i].familyOtherBlues[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[i].blueScale); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[i].blueScale); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (privateDicts[i].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[i].blueShift); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[i].blueShift); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (privateDicts[i].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[i].blueFuzz); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/BlueFuzz {0:d} def\n", privateDicts[i].blueFuzz); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (privateDicts[i].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[i].stdHW); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[i].stdHW); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (privateDicts[i].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[i].stdVW); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapH[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%s%g", j > 0 ? " " : "", privateDicts[i].stemSnapV[j]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[i].forceBold ? "true" : "false"); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[i].forceBoldThreshold); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[i].forceBoldThreshold); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (privateDicts[i].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[i].languageGroup); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/ExpansionFactor %g def\n", - privateDicts[i].expansionFactor); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -627,26 +709,28 @@ void FoFiType1C::convertToCIDType0(char *psName, // start the binary section offset = (nCIDs + 1) * (1 + gdBytes); - sprintf(buf, "(Hex) %d StartData\n", - offset + charStrings->getLength()); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - buf[0] = (char)fdSelect[cidMap[i+j]]; + buf2[0] = (char)fdSelect[cidMap[i+j]]; } else { - buf[0] = (char)0; + buf2[0] = (char)0; } n = offset + charStringOffsets[i+j]; for (k = gdBytes; k >= 1; --k) { - buf[k] = (char)(n & 0xff); + buf2[k] = (char)(n & 0xff); n >>= 8; } for (k = 0; k <= gdBytes; ++k) { - sprintf(buf2, "%02x", buf[k] & 0xff); - (*outputFunc)(outputStream, buf2, 2); + buf = GString::format("{0:02x}", buf2[k] & 0xff); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } } (*outputFunc)(outputStream, "\n", 1); @@ -656,8 +740,9 @@ void FoFiType1C::convertToCIDType0(char *psName, n = charStrings->getLength(); for (i = 0; i < n; i += 32) { for (j = 0; j < 32 && i+j < n; ++j) { - sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -677,7 +762,7 @@ void FoFiType1C::convertToType0(char *psName, Type1CIndex subrIdx; Type1CIndexVal val; int nCIDs; - char buf[512]; + GString *buf; Type1CEexecBuf eb; GBool ok; int fd, i, j, k; @@ -702,9 +787,9 @@ void FoFiType1C::convertToType0(char *psName, //~ 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 + //~ font up by FD; as a kludge we ignore CID 0, which is .notdef fd = 0; - for (j = 0; j < 256 && i+j < nCIDs; ++j) { + for (j = i==0 ? 1 : 0; j < 256 && i+j < nCIDs; ++j) { if (cidMap[i+j] >= 0) { fd = fdSelect[cidMap[i+j]]; break; @@ -715,42 +800,50 @@ void FoFiType1C::convertToType0(char *psName, (*outputFunc)(outputStream, "16 dict begin\n", 14); (*outputFunc)(outputStream, "/FontName /", 11); (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] 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, strlen(buf)); + 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); } - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - topDict.fontBBox[0], topDict.fontBBox[1], - topDict.fontBBox[2], topDict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/PaintType %d def\n", topDict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "/StrokeWidth %g def\n", topDict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); + buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j); + (*outputFunc)(outputStream, buf->getCString(), buf->getLength()); + delete buf; } if (j < 256) { - sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -775,91 +868,116 @@ void FoFiType1C::convertToType0(char *psName, if (privateDicts[fd].nBlueValues) { eexecWrite(&eb, "/BlueValues ["); for (k = 0; k < privateDicts[fd].nBlueValues; ++k) { - sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].blueValues[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", k > 0 ? " " : "", privateDicts[fd].otherBlues[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", k > 0 ? " " : "", - privateDicts[fd].familyBlues[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%d", k > 0 ? " " : "", - privateDicts[fd].familyOtherBlues[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "/BlueScale %g def\n", privateDicts[fd].blueScale); - eexecWrite(&eb, buf); + buf = GString::format("/BlueScale {0:.4g} def\n", + privateDicts[fd].blueScale); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].blueShift != 7) { - sprintf(buf, "/BlueShift %d def\n", privateDicts[fd].blueShift); - eexecWrite(&eb, buf); + buf = GString::format("/BlueShift {0:d} def\n", + privateDicts[fd].blueShift); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].blueFuzz != 1) { - sprintf(buf, "/BlueFuzz %d def\n", privateDicts[fd].blueFuzz); - eexecWrite(&eb, buf); + buf = GString::format("/BlueFuzz {0:d} def\n", + privateDicts[fd].blueFuzz); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].hasStdHW) { - sprintf(buf, "/StdHW [%g] def\n", privateDicts[fd].stdHW); - eexecWrite(&eb, buf); + buf = GString::format("/StdHW [{0:.4g}] def\n", privateDicts[fd].stdHW); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].hasStdVW) { - sprintf(buf, "/StdVW [%g] def\n", privateDicts[fd].stdVW); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "%s%g", k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]); - eexecWrite(&eb, buf); + 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) { - sprintf(buf, "/ForceBold %s def\n", - privateDicts[fd].forceBold ? "true" : "false"); - eexecWrite(&eb, buf); + buf = GString::format("/ForceBold {0:s} def\n", + privateDicts[fd].forceBold ? "true" : "false"); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].forceBoldThreshold != 0) { - sprintf(buf, "/ForceBoldThreshold %g def\n", - privateDicts[fd].forceBoldThreshold); - eexecWrite(&eb, buf); + buf = GString::format("/ForceBoldThreshold {0:.4g} def\n", + privateDicts[fd].forceBoldThreshold); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].languageGroup != 0) { - sprintf(buf, "/LanguageGroup %d def\n", privateDicts[fd].languageGroup); - eexecWrite(&eb, buf); + buf = GString::format("/LanguageGroup {0:d} def\n", + privateDicts[fd].languageGroup); + eexecWrite(&eb, buf->getCString()); + delete buf; } if (privateDicts[fd].expansionFactor != 0.06) { - sprintf(buf, "/ExpansionFactor %g def\n", - privateDicts[fd].expansionFactor); - eexecWrite(&eb, buf); + buf = GString::format("/ExpansionFactor {0:.4g} def\n", + privateDicts[fd].expansionFactor); + eexecWrite(&eb, buf->getCString()); + delete buf; } // set up the subroutines @@ -870,8 +988,7 @@ void FoFiType1C::convertToType0(char *psName, } // start the CharStrings - sprintf(buf, "2 index /CharStrings 256 dict dup begin\n"); - eexecWrite(&eb, buf); + eexecWrite(&eb, "2 index /CharStrings 256 dict dup begin\n"); // write the .notdef CharString ok = gTrue; @@ -887,9 +1004,10 @@ void FoFiType1C::convertToType0(char *psName, ok = gTrue; getIndexVal(&charStringsIdx, cidMap[i+j], &val, &ok); if (ok) { - sprintf(buf, "c%02x", j); - eexecCvtGlyph(&eb, buf, val.pos, val.len, + buf = GString::format("c{0:02x}", j); + eexecCvtGlyph(&eb, buf->getCString(), val.pos, val.len, &subrIdx, &privateDicts[fd]); + delete buf; } } } @@ -917,27 +1035,30 @@ void FoFiType1C::convertToType0(char *psName, (*outputFunc)(outputStream, " def\n", 5); (*outputFunc)(outputStream, "/FontType 0 def\n", 16); if (topDict.hasFontMatrix) { - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - topDict.fontMatrix[0], topDict.fontMatrix[1], - topDict.fontMatrix[2], topDict.fontMatrix[3], - topDict.fontMatrix[4], topDict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); + 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); @@ -949,15 +1070,16 @@ void FoFiType1C::eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName, int offset, int nBytes, Type1CIndex *subrIdx, Type1CPrivateDict *pDict) { - char buf[512]; + GString *buf; GString *charBuf; // generate the charstring charBuf = new GString(); cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue); - sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength()); - eexecWrite(eb, buf); + 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"); diff --git a/Build/source/libs/xpdf/fofi/FoFiType1C.h b/Build/source/libs/xpdf/fofi/FoFiType1C.h index 62649ed949d..eec27555494 100644 --- a/Build/source/libs/xpdf/fofi/FoFiType1C.h +++ b/Build/source/libs/xpdf/fofi/FoFiType1C.h @@ -157,8 +157,9 @@ public: // file. This is only useful with 8-bit fonts. If <newEncoding> is // not NULL, it will be used in place of the encoding in the Type 1C // font. If <ascii> is true the eexec section will be hex-encoded, - // otherwise it will be left as binary data. - void convertToType1(char **newEncoding, GBool ascii, + // otherwise it will be left as binary data. If <psName> is non-NULL, + // it will be used as the PostScript font name. + void convertToType1(char *psName, char **newEncoding, GBool ascii, FoFiOutputFunc outputFunc, void *outputStream); // Convert to a Type 0 CIDFont, suitable for embedding in a diff --git a/Build/source/libs/xpdf/goo/FixedPoint.cc b/Build/source/libs/xpdf/goo/FixedPoint.cc index f969959a66b..47c2834a34b 100644 --- a/Build/source/libs/xpdf/goo/FixedPoint.cc +++ b/Build/source/libs/xpdf/goo/FixedPoint.cc @@ -18,13 +18,15 @@ #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; + y1.val = x.val == 1 ? 2 : x.val >> 1; do { y0.val = y1.val; z = x / y0; @@ -34,10 +36,9 @@ FixedPoint FixedPoint::sqrt(FixedPoint x) { return y1; } -//~ this is not very accurate FixedPoint FixedPoint::pow(FixedPoint x, FixedPoint y) { FixedPoint t, t2, lnx0, lnx, z0, z; - int d, i; + int d, n, i; if (y.val <= 0) { z.val = 0; @@ -56,6 +57,8 @@ FixedPoint FixedPoint::pow(FixedPoint x, FixedPoint y) { lnx.val <<= 1; t = y * lnx; // exp(y * ln(x)) + n = floor(t / ln2); + t -= ln2 * n; t2 = t; d = 1; i = 1; @@ -67,6 +70,11 @@ FixedPoint FixedPoint::pow(FixedPoint x, FixedPoint y) { ++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; } @@ -92,4 +100,19 @@ int FixedPoint::div(int x, int y) { #endif } +GBool FixedPoint::divCheck(FixedPoint x, FixedPoint y, FixedPoint *result) { +#if 1 //~tmp + 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; +#else +#endif +} + #endif // USE_FIXEDPOINT diff --git a/Build/source/libs/xpdf/goo/FixedPoint.h b/Build/source/libs/xpdf/goo/FixedPoint.h index 7e89018edb9..abcb212101d 100644 --- a/Build/source/libs/xpdf/goo/FixedPoint.h +++ b/Build/source/libs/xpdf/goo/FixedPoint.h @@ -21,6 +21,7 @@ #include <stdio.h> #include <stdlib.h> +#include "gtypes.h" #define fixptShift 16 #define fixptMaskL ((1 << fixptShift) - 1) @@ -135,6 +136,10 @@ public: 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); + private: static FixedPoint make(int valA) { FixedPoint x; x.val = valA; return x; } diff --git a/Build/source/libs/xpdf/goo/GString.cc b/Build/source/libs/xpdf/goo/GString.cc index 049dcf38dc9..de280ad9842 100644 --- a/Build/source/libs/xpdf/goo/GString.cc +++ b/Build/source/libs/xpdf/goo/GString.cc @@ -18,14 +18,66 @@ #include <stddef.h> #include <string.h> #include <ctype.h> -#include "gtypes.h" +#include <math.h> +#include "gmem.h" #include "GString.h" +//------------------------------------------------------------------------ + +union GStringFormatArg { + int i; + Guint ui; + long l; + Gulong ul; + 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, + fmtDouble, + fmtDoubleTrim, + fmtChar, + fmtString, + fmtGString, + fmtSpace +}; + +static char *formatStrings[] = { + "d", "x", "o", "b", "ud", "ux", "uo", "ub", + "ld", "lx", "lo", "lb", "uld", "ulx", "ulo", "ulb", + "f", "g", + "c", + "s", + "t", + "w", + NULL +}; + +//------------------------------------------------------------------------ + static inline int size(int len) { int delta; - - delta = len < 256 ? 7 : 255; - return ((len + 1) + delta) & ~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) { @@ -92,28 +144,30 @@ GString::GString(GString *str1, GString *str2) { GString *GString::fromInt(int x) { char buf[24]; // enough space for 64-bit ints plus a little extra - GBool neg; - Guint y; - int i; + char *p; + int len; - i = 24; - if (x == 0) { - buf[--i] = '0'; - } else { - if ((neg = x < 0)) { - y = (Guint)-x; - } else { - y = (Guint)x; - } - while (i > 0 && y > 0) { - buf[--i] = '0' + y % 10; - y /= 10; - } - if (neg && i > 0) { - buf[--i] = '-'; - } - } - return new GString(buf + i, 24 - i); + formatInt(x, buf, sizeof(buf), gFalse, 0, 10, &p, &len); + return new GString(p, len); +} + +GString *GString::format(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(char *fmt, va_list argList) { + GString *s; + + s = new GString(); + s->appendfv(fmt, argList); + return s; } GString::~GString() { @@ -159,6 +213,351 @@ GString *GString::append(const char *str, int lengthA) { return this; } +GString *GString::appendf(char *fmt, ...) { + va_list argList; + + va_start(argList, fmt); + appendfv(fmt, argList); + va_end(argList); + return this; +} + +GString *GString::appendfv(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; + char *p0, *p1, *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 (*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; + 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; + 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 = 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, p1 - p0); + p0 = p1; + } + } + + gfree(args); + return this; +} + +void GString::formatInt(long x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len) { + 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; +} + +void GString::formatUInt(Gulong x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len) { + 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; diff --git a/Build/source/libs/xpdf/goo/GString.h b/Build/source/libs/xpdf/goo/GString.h index f4ff7c6a9ee..dd22e2d8f6b 100644 --- a/Build/source/libs/xpdf/goo/GString.h +++ b/Build/source/libs/xpdf/goo/GString.h @@ -17,6 +17,9 @@ #pragma interface #endif +#include <stdarg.h> +#include "gtypes.h" + class GString { public: @@ -43,6 +46,30 @@ public: // 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: + // {<arg>:[<width>][.<precision>]<type>} + // where: + // - <arg> 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 + // - <width> is the field width -- negative to reverse the alignment; + // starting with a leading zero to zero-fill (for integers) + // - <precision> is the number of digits to the right of the decimal + // point (for floating point numbers) + // - <type> 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 + // 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(char *fmt, ...); + static GString *formatv(char *fmt, va_list argList); + // Destructor. ~GString(); @@ -67,6 +94,10 @@ public: GString *append(const char *str); GString *append(const char *str, int lengthA); + // Append a formatted string. + GString *appendf(char *fmt, ...); + GString *appendfv(char *fmt, va_list argList); + // Insert a character or string. GString *insert(int i, char c); GString *insert(int i, GString *str); @@ -92,6 +123,14 @@ private: char *s; void resize(int length1); + static void formatInt(long x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len); + static void formatUInt(Gulong x, char *buf, int bufSize, + GBool zeroFill, int width, int base, + char **p, int *len); + static void formatDouble(double x, char *buf, int bufSize, int prec, + GBool trim, char **p, int *len); }; #endif diff --git a/Build/source/libs/xpdf/goo/Makefile.in b/Build/source/libs/xpdf/goo/Makefile.in index fe992f46ac5..4cebea29e0b 100644 --- a/Build/source/libs/xpdf/goo/Makefile.in +++ b/Build/source/libs/xpdf/goo/Makefile.in @@ -5,6 +5,7 @@ # Copyright 1996 Derek B. Noonburg # # Modified for pdftex by Martin Schröder 2005 +# $Id$ # #======================================================================== @@ -43,17 +44,17 @@ CXX_SRC = \ $(srcdir)/GHash.cc \ $(srcdir)/GList.cc \ $(srcdir)/GString.cc \ + $(srcdir)/gmem.cc \ $(srcdir)/gmempp.cc \ $(srcdir)/gfile.cc C_SRC = \ - $(srcdir)/gmem.c \ $(srcdir)/parseargs.c #------------------------------------------------------------------------ -GOO_CXX_OBJS = FixedPoint.o GHash.o GList.o GString.o gmempp.o gfile.o -GOO_C_OBJS = gmem.o parseargs.o +GOO_CXX_OBJS = FixedPoint.o GHash.o GList.o GString.o gmem.o gmempp.o gfile.o +GOO_C_OBJS = parseargs.o GOO_OBJS = $(GOO_CXX_OBJS) $(GOO_C_OBJS) libGoo.a: $(GOO_OBJS) diff --git a/Build/source/libs/xpdf/goo/depend.mk b/Build/source/libs/xpdf/goo/depend.mk index c0dfb37f7b5..8aa02de24cb 100644 --- a/Build/source/libs/xpdf/goo/depend.mk +++ b/Build/source/libs/xpdf/goo/depend.mk @@ -23,7 +23,7 @@ GString.o: $(srcdir)/GString.cc ../aconf.h \ $(srcdirparent)/aconf2.h \ $(srcdir)/gtypes.h \ $(srcdir)/GString.h -gmem.o: $(srcdir)/gmem.c ../aconf.h \ +gmem.o: $(srcdir)/gmem.cc ../aconf.h \ $(srcdirparent)/aconf2.h \ $(srcdir)/gmem.h parseargs.o: $(srcdir)/parseargs.c \ diff --git a/Build/source/libs/xpdf/goo/gfile.cc b/Build/source/libs/xpdf/goo/gfile.cc index caa96e7459b..740b3ea1ff6 100644 --- a/Build/source/libs/xpdf/goo/gfile.cc +++ b/Build/source/libs/xpdf/goo/gfile.cc @@ -10,7 +10,9 @@ #include <aconf.h> -#ifndef WIN32 +#ifdef WIN32 +# include <time.h> +#else # if defined(MACOS) # include <sys/stat.h> # elif !defined(ACORN) @@ -441,21 +443,45 @@ time_t getModTime(char *fileName) { GBool openTempFile(GString **name, FILE **f, char *mode, char *ext) { #if defined(WIN32) //---------- Win32 ---------- - char *s; - - if (!(s = _tempnam(getenv("TEMP"), NULL))) { - return gFalse; - } - *name = new GString(s); - free(s); - if (ext) { - (*name)->append(ext); + char *tempDir; + GString *s, *s2; + char buf[32]; + 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(); } - if (!(*f = fopen((*name)->getCString(), mode))) { - delete (*name); - return gFalse; + s->append("x"); + t = (int)time(NULL); + for (i = 0; i < 1000; ++i) { + sprintf(buf, "%d", t + i); + s2 = s->copy()->append(buf); + 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; } - return gTrue; + delete s; + return gFalse; #elif defined(VMS) || defined(__EMX__) || defined(ACORN) || defined(MACOS) //---------- non-Unix ---------- char *s; @@ -672,9 +698,9 @@ GDirEntry *GDir::getNextEntry() { struct dirent *ent; e = NULL; if (dir) { - ent = readdir(dir); + ent = (struct dirent *)readdir(dir); if (ent && !strcmp(ent->d_name, ".")) { - ent = readdir(dir); + ent = (struct dirent *)readdir(dir); } if (ent) { e = new GDirEntry(path->getCString(), ent->d_name, doStat); diff --git a/Build/source/libs/xpdf/goo/gfile.h b/Build/source/libs/xpdf/goo/gfile.h index 8817e8b2381..82f1d7a98e3 100644 --- a/Build/source/libs/xpdf/goo/gfile.h +++ b/Build/source/libs/xpdf/goo/gfile.h @@ -46,9 +46,6 @@ # endif # endif #endif -#if defined(__DJGPP__) -typedef unsigned int time_t; -#endif #include "gtypes.h" class GString; @@ -86,9 +83,7 @@ extern time_t getModTime(char *fileName); // should be done to the returned file pointer; the file may be // reopened later for reading, but not for writing. The <mode> string // should be "w" or "wb". Returns true on success. -#ifndef PDF_PARSER_ONLY extern GBool openTempFile(GString **name, FILE **f, char *mode, char *ext); -#endif // Execute <command>. Returns true on success. extern GBool executeCommand(char *cmd); diff --git a/Build/source/libs/xpdf/goo/gmem.c b/Build/source/libs/xpdf/goo/gmem.cc index b97535adf04..6b13b38d0f0 100644 --- a/Build/source/libs/xpdf/goo/gmem.c +++ b/Build/source/libs/xpdf/goo/gmem.cc @@ -17,14 +17,17 @@ #ifdef DEBUG_MEM typedef struct _GMemHdr { + unsigned int magic; int size; int index; - struct _GMemHdr *next; + 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 @@ -35,19 +38,8 @@ typedef struct _GMemHdr { #define gMemDataSize(size) \ ((((size) + gMemTrlSize - 1) / gMemTrlSize) * gMemTrlSize) -#define gMemNLists 64 -#define gMemListShift 4 -#define gMemListMask (gMemNLists - 1) -static GMemHdr *gMemList[gMemNLists] = { - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL -}; +static GMemHdr *gMemHead = NULL; +static GMemHdr *gMemTail = NULL; static int gMemIndex = 0; static int gMemAlloc = 0; @@ -55,57 +47,75 @@ static int gMemInUse = 0; #endif /* DEBUG_MEM */ -void *gmalloc(int size) { +void *gmalloc(int size) GMEM_EXCEP { #ifdef DEBUG_MEM int size1; char *mem; GMemHdr *hdr; void *data; - int lst; unsigned long *trl, *p; - if (size <= 0) + 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++; - lst = ((int)hdr >> gMemListShift) & gMemListMask; - hdr->next = gMemList[lst]; - gMemList[lst] = hdr; + 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) + for (p = (unsigned long *)data; p <= trl; ++p) { *p = gMemDeadVal; + } return data; #else void *p; - if (size <= 0) + 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) { +void *grealloc(void *p, int size) GMEM_EXCEP { #ifdef DEBUG_MEM GMemHdr *hdr; void *q; int oldSize; if (size <= 0) { - if (p) + if (p) { gfree(p); + } return NULL; } if (p) { @@ -122,23 +132,29 @@ void *grealloc(void *p, int size) { void *q; if (size <= 0) { - if (p) + if (p) { free(p); + } return NULL; } - if (p) + if (p) { q = realloc(p, size); - else + } 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) { +void *gmallocn(int nObjs, int objSize) GMEM_EXCEP { int n; if (nObjs == 0) { @@ -146,13 +162,17 @@ void *gmallocn(int nObjs, int objSize) { } 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) { +void *greallocn(void *p, int nObjs, int objSize) GMEM_EXCEP { int n; if (nObjs == 0) { @@ -163,8 +183,12 @@ void *greallocn(void *p, int nObjs, int objSize) { } 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); } @@ -173,22 +197,23 @@ void gfree(void *p) { #ifdef DEBUG_MEM int size; GMemHdr *hdr; - GMemHdr *prevHdr, *q; - int lst; unsigned long *trl, *clr; if (p) { hdr = (GMemHdr *)((char *)p - gMemHdrSize); - lst = ((int)hdr >> gMemListShift) & gMemListMask; - for (prevHdr = NULL, q = gMemList[lst]; q; prevHdr = q, q = q->next) { - if (q == hdr) - break; - } - if (q) { - if (prevHdr) - prevHdr->next = hdr->next; - else - gMemList[lst] = hdr->next; + 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); @@ -197,32 +222,32 @@ void gfree(void *p) { fprintf(stderr, "Overwrite past end of block %d at address %p\n", hdr->index, p); } - for (clr = (unsigned long *)hdr; clr <= trl; ++clr) + 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) + if (p) { free(p); + } #endif } #ifdef DEBUG_MEM void gMemReport(FILE *f) { GMemHdr *p; - int lst; 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 (lst = 0; lst < gMemNLists; ++lst) { - for (p = gMemList[lst]; p; p = p->next) - fprintf(f, "%8d %8d\n", p->index, p->size); + 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"); diff --git a/Build/source/libs/xpdf/goo/gmem.h b/Build/source/libs/xpdf/goo/gmem.h index e74d1822318..da34736f216 100644 --- a/Build/source/libs/xpdf/goo/gmem.h +++ b/Build/source/libs/xpdf/goo/gmem.h @@ -10,6 +10,23 @@ #define GMEM_H #include <stdio.h> +#include <aconf.h> + +#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" { @@ -19,13 +36,13 @@ extern "C" { * Same as malloc, but prints error message and exits if malloc() * returns NULL. */ -extern void *gmalloc(int size); +extern void *gmalloc(int size) GMEM_EXCEP; /* * Same as realloc, but prints error message and exits if realloc() * returns NULL. If <p> is NULL, calls malloc instead of realloc(). */ -extern void *grealloc(void *p, int size); +extern void *grealloc(void *p, int size) GMEM_EXCEP; /* * These are similar to gmalloc and grealloc, but take an object count @@ -33,8 +50,8 @@ extern void *grealloc(void *p, int size); * bytes, but there is an additional error check that the total size * doesn't overflow an int. */ -extern void *gmallocn(int nObjs, int objSize); -extern void *greallocn(void *p, int nObjs, int objSize); +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. diff --git a/Build/source/libs/xpdf/xpdf/Catalog.cc b/Build/source/libs/xpdf/xpdf/Catalog.cc index fd235d63c4b..de282c3feb6 100644 --- a/Build/source/libs/xpdf/xpdf/Catalog.cc +++ b/Build/source/libs/xpdf/xpdf/Catalog.cc @@ -2,7 +2,7 @@ // // Catalog.cc // -// Copyright 1996-2003 Glyph & Cog, LLC +// Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== @@ -28,8 +28,9 @@ //------------------------------------------------------------------------ Catalog::Catalog(XRef *xrefA) { - Object catDict, pagesDict; + Object catDict, pagesDict, pagesDictRef; Object obj, obj2; + char *alreadyRead; int numPages0; int i; @@ -71,7 +72,16 @@ Catalog::Catalog(XRef *xrefA) { pageRefs[i].num = -1; pageRefs[i].gen = -1; } - numPages = readPageTree(pagesDict.getDict(), NULL, 0); + alreadyRead = (char *)gmalloc(xref->getNumObjects()); + memset(alreadyRead, 0, xref->getNumObjects()); + if (catDict.dictLookupNF("Pages", &pagesDictRef)->isRef() && + pagesDictRef.getRefNum() >= 0 && + pagesDictRef.getRefNum() < xref->getNumObjects()) { + alreadyRead[pagesDictRef.getRefNum()] = 1; + } + pagesDictRef.free(); + numPages = readPageTree(pagesDict.getDict(), NULL, 0, alreadyRead); + gfree(alreadyRead); if (numPages != numPages0) { error(-1, "Page count in top-level pages object is incorrect"); } @@ -169,7 +179,8 @@ GString *Catalog::readMetadata() { return s; } -int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { +int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start, + char *alreadyRead) { Object kids; Object kid; Object kidRef; @@ -185,6 +196,17 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { goto err1; } for (i = 0; i < kids.arrayGetLength(); ++i) { + kids.arrayGetNF(i, &kidRef); + if (kidRef.isRef() && + kidRef.getRefNum() >= 0 && + kidRef.getRefNum() < xref->getNumObjects()) { + if (alreadyRead[kidRef.getRefNum()]) { + error(-1, "Loop in Pages tree"); + kidRef.free(); + continue; + } + alreadyRead[kidRef.getRefNum()] = 1; + } kids.arrayGet(i, &kid); if (kid.isDict("Page")) { attrs2 = new PageAttrs(attrs1, kid.getDict()); @@ -204,17 +226,15 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { } } pages[start] = page; - kids.arrayGetNF(i, &kidRef); if (kidRef.isRef()) { pageRefs[start].num = kidRef.getRefNum(); pageRefs[start].gen = kidRef.getRefGen(); } - kidRef.free(); ++start; // This should really be isDict("Pages"), but I've seen at least one // PDF file where the /Type entry is missing. } else if (kid.isDict()) { - if ((start = readPageTree(kid.getDict(), attrs1, start)) + if ((start = readPageTree(kid.getDict(), attrs1, start, alreadyRead)) < 0) goto err2; } else { @@ -222,6 +242,7 @@ int Catalog::readPageTree(Dict *pagesDict, PageAttrs *attrs, int start) { start+1, kid.getTypeName()); } kid.free(); + kidRef.free(); } delete attrs1; kids.free(); diff --git a/Build/source/libs/xpdf/xpdf/Catalog.h b/Build/source/libs/xpdf/xpdf/Catalog.h index c38f1098500..6403194f974 100644 --- a/Build/source/libs/xpdf/xpdf/Catalog.h +++ b/Build/source/libs/xpdf/xpdf/Catalog.h @@ -2,7 +2,7 @@ // // Catalog.h // -// Copyright 1996-2003 Glyph & Cog, LLC +// Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== @@ -65,6 +65,10 @@ public: // NULL if <name> is not a destination. LinkDest *findDest(GString *name); + Object *getDests() { return &dests; } + + Object *getNameTree() { return &nameTree; } + Object *getOutline() { return &outline; } Object *getAcroForm() { return &acroForm; } @@ -85,7 +89,8 @@ private: Object acroForm; // AcroForm dictionary GBool ok; // true if catalog is valid - int readPageTree(Dict *pages, PageAttrs *attrs, int start); + int readPageTree(Dict *pages, PageAttrs *attrs, int start, + char *alreadyRead); Object *findDestInTree(Object *tree, GString *name, Object *obj); }; diff --git a/Build/source/libs/xpdf/xpdf/Decrypt.cc b/Build/source/libs/xpdf/xpdf/Decrypt.cc index 91eb452a815..03205897cf4 100644 --- a/Build/source/libs/xpdf/xpdf/Decrypt.cc +++ b/Build/source/libs/xpdf/xpdf/Decrypt.cc @@ -18,6 +18,9 @@ static void rc4InitKey(Guchar *key, int keyLen, Guchar *state); static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c); +static void aesKeyExpansion(DecryptAESState *s, + Guchar *objKey, int objKeyLen); +static void aesDecryptBlock(DecryptAESState *s, Guchar *in, GBool last); static void md5(Guchar *msg, int msgLen, Guchar *digest); static Guchar passwordPad[32] = { @@ -31,37 +34,6 @@ static Guchar passwordPad[32] = { // Decrypt //------------------------------------------------------------------------ -Decrypt::Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen) { - int i; - - // construct object key - for (i = 0; i < keyLength; ++i) { - objKey[i] = fileKey[i]; - } - 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); - - // set up for decryption - x = y = 0; - if ((objKeyLength = keyLength + 5) > 16) { - objKeyLength = 16; - } - rc4InitKey(objKey, objKeyLength, state); -} - -void Decrypt::reset() { - x = y = 0; - rc4InitKey(objKey, objKeyLength, state); -} - -Guchar Decrypt::decryptByte(Guchar c) { - return rc4DecryptByte(state, &x, &y, c); -} - GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength, GString *ownerKey, GString *userKey, int permissions, GString *fileID, @@ -206,6 +178,144 @@ GBool Decrypt::makeFileKey2(int encVersion, int encRevision, int keyLength, } //------------------------------------------------------------------------ +// DecryptStream +//------------------------------------------------------------------------ + +DecryptStream::DecryptStream(Stream *strA, Guchar *fileKey, + CryptAlgorithm algoA, int keyLength, + int objNum, int objGen): + FilterStream(strA) +{ + int n, i; + + algo = algoA; + + // construct object key + for (i = 0; i < keyLength; ++i) { + objKey[i] = fileKey[i]; + } + 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; + if (algo == cryptAES) { + objKey[keyLength + 5] = 0x73; // 's' + objKey[keyLength + 6] = 0x41; // 'A' + objKey[keyLength + 7] = 0x6c; // 'l' + objKey[keyLength + 8] = 0x54; // 'T' + n = keyLength + 9; + } else { + n = keyLength + 5; + } + md5(objKey, n, objKey); + if ((objKeyLength = keyLength + 5) > 16) { + objKeyLength = 16; + } +} + +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; + } +} + +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; + } + 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; + } + return c; +} + +GBool DecryptStream::isBinary(GBool last) { + return str->isBinary(last); +} + +//------------------------------------------------------------------------ // RC4-compatible decryption //------------------------------------------------------------------------ @@ -239,6 +349,261 @@ static Guchar rc4DecryptByte(Guchar *state, Guchar *x, Guchar *y, Guchar c) { } //------------------------------------------------------------------------ +// 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]; + for (i = 15; i >= n; --i) { + s->buf[i] = s->buf[i-n]; + } + s->bufIdx = n; + } +} + +//------------------------------------------------------------------------ // MD5 message digest //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/xpdf/Decrypt.h b/Build/source/libs/xpdf/xpdf/Decrypt.h index 2beba581583..56f34b77f26 100644 --- a/Build/source/libs/xpdf/xpdf/Decrypt.h +++ b/Build/source/libs/xpdf/xpdf/Decrypt.h @@ -17,6 +17,8 @@ #include "gtypes.h" #include "GString.h" +#include "Object.h" +#include "Stream.h" //------------------------------------------------------------------------ // Decrypt @@ -25,15 +27,6 @@ class Decrypt { public: - // Initialize the decryptor object. - Decrypt(Guchar *fileKey, int keyLength, int objNum, int objGen); - - // Reset decryption. - void reset(); - - // Decrypt one byte. - Guchar decryptByte(Guchar c); - // Generate a file key. The <fileKey> buffer must have space for at // least 16 bytes. Checks <ownerPassword> and then <userPassword> // and returns true if either is correct. Sets <ownerPasswordOk> if @@ -53,11 +46,50 @@ private: int permissions, GString *fileID, GString *userPassword, Guchar *fileKey, GBool encryptMetadata); +}; - int objKeyLength; - Guchar objKey[21]; +//------------------------------------------------------------------------ +// 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; +}; + +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[16 + 9]; + + union { + DecryptRC4State rc4; + DecryptAESState aes; + } state; }; #endif diff --git a/Build/source/libs/xpdf/xpdf/Function.cc b/Build/source/libs/xpdf/xpdf/Function.cc index f6996412a8b..a4d51c73821 100644 --- a/Build/source/libs/xpdf/xpdf/Function.cc +++ b/Build/source/libs/xpdf/xpdf/Function.cc @@ -190,10 +190,11 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { Object obj1, obj2; Guint buf, bitMask; int bits; - int s; + Guint s; int i; samples = NULL; + sBuf = NULL; ok = gFalse; //----- initialize the generic stuff @@ -204,6 +205,14 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { error(-1, "Type 0 function is missing range"); goto err1; } + if (m > sampledFuncMaxInputs) { + error(-1, "Sampled functions with more than %d inputs are unsupported", + sampledFuncMaxInputs); + goto err1; + } + + //----- buffer + sBuf = (double *)gmallocn(1 << m, sizeof(double)); //----- get the stream if (!funcObj->isStream()) { @@ -239,7 +248,7 @@ SampledFunction::SampledFunction(Object *funcObj, Dict *dict) { goto err2; } sampleBits = obj1.getInt(); - sampleMul = 1.0 / (double)((1 << sampleBits) - 1); + sampleMul = 1.0 / (pow(2.0, (double)sampleBits) - 1); obj1.free(); //----- Encode @@ -347,12 +356,16 @@ SampledFunction::~SampledFunction() { if (samples) { gfree(samples); } + if (sBuf) { + gfree(sBuf); + } } SampledFunction::SampledFunction(SampledFunction *func) { memcpy(this, func, sizeof(SampledFunction)); 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) { @@ -360,7 +373,6 @@ void SampledFunction::transform(double *in, double *out) { int e[funcMaxInputs][2]; double efrac0[funcMaxInputs]; double efrac1[funcMaxInputs]; - double s[1 << funcMaxInputs]; int i, j, k, idx, t; // map input values into sample array @@ -389,18 +401,18 @@ void SampledFunction::transform(double *in, double *out) { for (k = 0, t = j; k < m; ++k, t >>= 1) { idx += idxMul[k] * (e[k][t & 1]); } - s[j] = samples[idx]; + sBuf[j] = samples[idx]; } // do m sets of interpolations for (j = 0, t = (1<<m); j < m; ++j, t >>= 1) { for (k = 0; k < t; k += 2) { - s[k >> 1] = efrac0[j] * s[k] + efrac1[j] * s[k+1]; + sBuf[k >> 1] = efrac0[j] * sBuf[k] + efrac1[j] * sBuf[k+1]; } } // map output value to range - out[i] = s[0] * (decode[i][1] - decode[i][0]) + decode[i][0]; + 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]) { @@ -540,6 +552,7 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { funcs = NULL; bounds = NULL; encode = NULL; + scale = NULL; //----- initialize the generic stuff if (!init(dict)) { @@ -559,6 +572,7 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { 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; } @@ -609,6 +623,17 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) { } 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; @@ -630,6 +655,8 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) { 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; } @@ -646,6 +673,7 @@ StitchingFunction::~StitchingFunction() { gfree(funcs); gfree(bounds); gfree(encode); + gfree(scale); } void StitchingFunction::transform(double *in, double *out) { @@ -664,8 +692,7 @@ void StitchingFunction::transform(double *in, double *out) { break; } } - x = encode[2*i] + ((x - bounds[i]) / (bounds[i+1] - bounds[i])) * - (encode[2*i+1] - encode[2*i]); + x = encode[2*i] + (x - bounds[i]) * scale[i]; funcs[i]->transform(&x, out); } @@ -1180,14 +1207,25 @@ GBool PostScriptFunction::parseCode(Stream *str, int *codePtr) { GString *PostScriptFunction::getToken(Stream *str) { GString *s; int c; + GBool comment; s = new GString(); - do { - c = str->getChar(); - if (c != EOF) { - codeString->append(c); + comment = gFalse; + while (1) { + if ((c = str->getChar()) == EOF) { + break; } - } while (c != EOF && isspace(c)); + 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 == '-') { diff --git a/Build/source/libs/xpdf/xpdf/Function.h b/Build/source/libs/xpdf/xpdf/Function.h index bfaf83e300e..334a4390fa1 100644 --- a/Build/source/libs/xpdf/xpdf/Function.h +++ b/Build/source/libs/xpdf/xpdf/Function.h @@ -27,8 +27,9 @@ class PSStack; // Function //------------------------------------------------------------------------ -#define funcMaxInputs 8 -#define funcMaxOutputs 32 +#define funcMaxInputs 32 +#define funcMaxOutputs 32 +#define sampledFuncMaxInputs 16 class Function { public: @@ -131,6 +132,7 @@ private: int idxMul[funcMaxInputs]; // sample array index multipliers double *samples; // the samples int nSamples; // size of the samples array + double *sBuf; // buffer for the transform function GBool ok; }; @@ -180,6 +182,7 @@ public: Function *getFunc(int i) { return funcs[i]; } double *getBounds() { return bounds; } double *getEncode() { return encode; } + double *getScale() { return scale; } private: @@ -189,6 +192,7 @@ private: Function **funcs; double *bounds; double *encode; + double *scale; GBool ok; }; diff --git a/Build/source/libs/xpdf/xpdf/GfxFont.cc b/Build/source/libs/xpdf/xpdf/GfxFont.cc index a4581c0ff35..9af7efcf8c6 100644 --- a/Build/source/libs/xpdf/xpdf/GfxFont.cc +++ b/Build/source/libs/xpdf/xpdf/GfxFont.cc @@ -235,6 +235,19 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) { error(-1, "Mismatch between font type and embedded font file"); } type = fontCIDType0C; + } else if (obj4.isName("OpenType")) { + embFontID = obj2.getRef(); + if (type == fontTrueType) { + type = fontTrueTypeOT; + } else if (type == fontType1) { + type = fontType1COT; + } else if (type == fontCIDType0) { + type = fontCIDType0COT; + } else if (type == fontCIDType2) { + type = fontCIDType2OT; + } else { + error(-1, "Mismatch between font type and embedded font file"); + } } else { error(-1, "Unknown embedded font type '%s'", obj4.isName() ? obj4.getName() : "???"); @@ -751,6 +764,15 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } } + + // 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 @@ -973,10 +995,10 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { useMacRoman = gTrue; } } else { - if (macRomanCmap >= 0) { - cmap = macRomanCmap; - } else if (msSymbolCmap >= 0) { + if (msSymbolCmap >= 0) { cmap = msSymbolCmap; + } else if (macRomanCmap >= 0) { + cmap = macRomanCmap; } } diff --git a/Build/source/libs/xpdf/xpdf/GfxFont.h b/Build/source/libs/xpdf/xpdf/GfxFont.h index 62dfd0881ad..d076692fc86 100644 --- a/Build/source/libs/xpdf/xpdf/GfxFont.h +++ b/Build/source/libs/xpdf/xpdf/GfxFont.h @@ -35,12 +35,16 @@ enum GfxFontType { fontUnknownType, fontType1, fontType1C, + fontType1COT, fontType3, fontTrueType, + fontTrueTypeOT, //----- GfxCIDFont fontCIDType0, fontCIDType0C, - fontCIDType2 + fontCIDType0COT, + fontCIDType2, + fontCIDType2OT }; //------------------------------------------------------------------------ @@ -127,6 +131,7 @@ public: GString *getExtFontFile() { return extFontFile; } // Get font descriptor flags. + int getFlags() { return flags; } GBool isFixedWidth() { return flags & fontFixedWidth; } GBool isSerif() { return flags & fontSerif; } GBool isSymbolic() { return flags & fontSymbolic; } diff --git a/Build/source/libs/xpdf/xpdf/GfxState.cc b/Build/source/libs/xpdf/xpdf/GfxState.cc index 051c7b645c8..67b4f6fd92d 100644 --- a/Build/source/libs/xpdf/xpdf/GfxState.cc +++ b/Build/source/libs/xpdf/xpdf/GfxState.cc @@ -34,10 +34,12 @@ static inline double clip01(double x) { //------------------------------------------------------------------------ -static struct { +struct GfxBlendModeInfo { char *name; GfxBlendMode mode; -} gfxBlendModeNames[] = { +}; + +static GfxBlendModeInfo gfxBlendModeNames[] = { { "Normal", gfxBlendNormal }, { "Compatible", gfxBlendNormal }, { "Multiply", gfxBlendMultiply }, @@ -58,7 +60,7 @@ static struct { }; #define nGfxBlendModeNames \ - ((int)((sizeof(gfxBlendModeNames) / sizeof(char *)))) + ((int)((sizeof(gfxBlendModeNames) / sizeof(GfxBlendModeInfo)))) //------------------------------------------------------------------------ @@ -186,6 +188,10 @@ void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = clip01(gfxColorComp1 - color->c[0]); } +void GfxDeviceGrayColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + //------------------------------------------------------------------------ // GfxCalGrayColorSpace //------------------------------------------------------------------------ @@ -271,6 +277,10 @@ void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = clip01(gfxColorComp1 - color->c[0]); } +void GfxCalGrayColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + //------------------------------------------------------------------------ // GfxDeviceRGBColorSpace //------------------------------------------------------------------------ @@ -316,6 +326,12 @@ void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxDeviceRGBColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + color->c[1] = 0; + color->c[2] = 0; +} + //------------------------------------------------------------------------ // GfxCalRGBColorSpace //------------------------------------------------------------------------ @@ -447,6 +463,12 @@ void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = k; } +void GfxCalRGBColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; + color->c[1] = 0; + color->c[2] = 0; +} + //------------------------------------------------------------------------ // GfxDeviceCMYKColorSpace //------------------------------------------------------------------------ @@ -537,6 +559,13 @@ void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { 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 //------------------------------------------------------------------------ @@ -714,6 +743,24 @@ void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { 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; @@ -839,6 +886,20 @@ 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) { @@ -991,6 +1052,10 @@ void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { base->getCMYK(mapColorToBase(color, &color2), cmyk); } +void GfxIndexedColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = 0; +} + void GfxIndexedColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { @@ -1008,6 +1073,7 @@ GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA, name = nameA; alt = altA; func = funcA; + nonMarking = !name->cmp("None"); } GfxSeparationColorSpace::~GfxSeparationColorSpace() { @@ -1104,6 +1170,10 @@ void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { alt->getCMYK(&color2, cmyk); } +void GfxSeparationColorSpace::getDefaultColor(GfxColor *color) { + color->c[0] = gfxColorComp1; +} + //------------------------------------------------------------------------ // GfxDeviceNColorSpace //------------------------------------------------------------------------ @@ -1114,6 +1184,7 @@ GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA, nComps = nCompsA; alt = altA; func = funcA; + nonMarking = gFalse; } GfxDeviceNColorSpace::~GfxDeviceNColorSpace() { @@ -1134,6 +1205,7 @@ GfxColorSpace *GfxDeviceNColorSpace::copy() { for (i = 0; i < nComps; ++i) { cs->names[i] = names[i]->copy(); } + cs->nonMarking = nonMarking; return cs; } @@ -1183,8 +1255,12 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { } obj1.free(); cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA); + cs->nonMarking = gTrue; for (i = 0; i < nCompsA; ++i) { cs->names[i] = namesA[i]; + if (namesA[i]->cmp("None")) { + cs->nonMarking = gFalse; + } } return cs; @@ -1245,6 +1321,14 @@ void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { alt->getCMYK(&color2, cmyk); } +void GfxDeviceNColorSpace::getDefaultColor(GfxColor *color) { + int i; + + for (i = 0; i < nComps; ++i) { + color->c[i] = gfxColorComp1; + } +} + //------------------------------------------------------------------------ // GfxPatternColorSpace //------------------------------------------------------------------------ @@ -1300,6 +1384,10 @@ void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { cmyk->k = 1; } +void GfxPatternColorSpace::getDefaultColor(GfxColor *color) { + // not used +} + //------------------------------------------------------------------------ // Pattern //------------------------------------------------------------------------ @@ -3113,6 +3201,11 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, maxPixel = (1 << bits) - 1; colorSpace = colorSpaceA; + // initialize + for (k = 0; k < gfxColorMaxComps; ++k) { + lookup[k] = NULL; + } + // get decode map if (decode->isNull()) { nComps = colorSpace->getNComps(); @@ -3147,9 +3240,6 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, // Optimization: for Indexed and Separation color spaces (which have // only one component), we store color values in the lookup table // rather than component values. - for (k = 0; k < gfxColorMaxComps; ++k) { - lookup[k] = NULL; - } colorSpace2 = NULL; nComps2 = 0; if (colorSpace->getMode() == csIndexed) { @@ -3506,10 +3596,12 @@ void GfxPath::offset(double dx, double dy) { // GfxState //------------------------------------------------------------------------ -GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, +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; @@ -3566,6 +3658,7 @@ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, strokeOpacity = 1; fillOverprint = gFalse; strokeOverprint = gFalse; + transfer[0] = transfer[1] = transfer[2] = transfer[3] = NULL; lineWidth = 1; lineDash = NULL; @@ -3575,6 +3668,7 @@ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, lineJoin = 0; lineCap = 0; miterLimit = 10; + strokeAdjust = gFalse; font = NULL; fontSize = 0; @@ -3601,6 +3695,8 @@ GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, } GfxState::~GfxState() { + int i; + if (fillColorSpace) { delete fillColorSpace; } @@ -3613,6 +3709,11 @@ GfxState::~GfxState() { 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() @@ -3625,6 +3726,8 @@ GfxState::~GfxState() { // Used for copy(); GfxState::GfxState(GfxState *state) { + int i; + memcpy(this, state, sizeof(GfxState)); if (fillColorSpace) { fillColorSpace = state->fillColorSpace->copy(); @@ -3638,6 +3741,11 @@ GfxState::GfxState(GfxState *state) { 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)); @@ -3783,6 +3891,15 @@ void GfxState::concatCTM(double a, double b, double c, } } +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; @@ -3811,6 +3928,17 @@ void GfxState::setStrokePattern(GfxPattern *pattern) { 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); @@ -3865,6 +3993,69 @@ void GfxState::clip() { } } +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::textShift(double tx, double ty) { double dx, dy; diff --git a/Build/source/libs/xpdf/xpdf/GfxState.h b/Build/source/libs/xpdf/xpdf/GfxState.h index e1d68013dfc..f85643dcc63 100644 --- a/Build/source/libs/xpdf/xpdf/GfxState.h +++ b/Build/source/libs/xpdf/xpdf/GfxState.h @@ -148,11 +148,18 @@ public: // 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 <maxImgPixel>. 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 number of color space modes static int getNumColorSpaceModes(); @@ -179,6 +186,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); private: }; @@ -203,6 +211,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 1; } + virtual void getDefaultColor(GfxColor *color); // CalGray-specific access. double getWhiteX() { return whiteX; } @@ -237,6 +246,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 3; } + virtual void getDefaultColor(GfxColor *color); private: }; @@ -261,6 +271,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 3; } + virtual void getDefaultColor(GfxColor *color); // CalRGB-specific access. double getWhiteX() { return whiteX; } @@ -299,6 +310,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 4; } + virtual void getDefaultColor(GfxColor *color); private: }; @@ -323,6 +335,7 @@ public: 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); @@ -368,6 +381,7 @@ public: 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); @@ -404,6 +418,7 @@ public: 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); @@ -442,6 +457,9 @@ public: 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; } @@ -453,6 +471,7 @@ private: GString *name; // colorant name GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) + GBool nonMarking; }; //------------------------------------------------------------------------ @@ -475,6 +494,9 @@ public: 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]; } @@ -488,6 +510,7 @@ private: *names[gfxColorMaxComps]; GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) + GBool nonMarking; }; //------------------------------------------------------------------------ @@ -510,6 +533,7 @@ public: virtual void getCMYK(GfxColor *color, GfxCMYK *cmyk); virtual int getNComps() { return 0; } + virtual void getDefaultColor(GfxColor *color); // Pattern-specific access. GfxColorSpace *getUnder() { return under; } @@ -992,7 +1016,7 @@ public: // Construct a default GfxState, for a device with resolution <hDPI> // x <vDPI>, page box <pageBox>, page rotation <rotateA>, and // coordinate system specified by <upsideDown>. - GfxState(double hDPI, double vDPI, PDFRectangle *pageBox, + GfxState(double hDPIA, double vDPIA, PDFRectangle *pageBox, int rotateA, GBool upsideDown); // Destructor. @@ -1002,6 +1026,8 @@ public: GfxState *copy() { return new GfxState(this); } // Accessors. + double getHDPI() { return hDPI; } + double getVDPI() { return vDPI; } double *getCTM() { return ctm; } double getX1() { return px1; } double getY1() { return py1; } @@ -1033,6 +1059,7 @@ public: double getStrokeOpacity() { return strokeOpacity; } GBool getFillOverprint() { return fillOverprint; } GBool getStrokeOverprint() { return strokeOverprint; } + Function **getTransfer() { return transfer; } double getLineWidth() { return lineWidth; } void getLineDash(double **dash, int *length, double *start) { *dash = lineDash; *length = lineDashLength; *start = lineDashStart; } @@ -1040,6 +1067,7 @@ public: 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; } @@ -1087,6 +1115,7 @@ public: 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; } @@ -1098,12 +1127,14 @@ public: void setStrokeOpacity(double opac) { strokeOpacity = opac; } void setFillOverprint(GBool op) { fillOverprint = op; } void setStrokeOverprint(GBool op) { strokeOverprint = op; } + 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, @@ -1137,6 +1168,7 @@ public: // Update clip region. void clip(); + void clipToStrokePath(); // Text position. void textSetPos(double tx, double ty) { lineX = tx; lineY = ty; } @@ -1155,6 +1187,7 @@ public: 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) @@ -1171,6 +1204,10 @@ private: double strokeOpacity; // stroke opacity GBool fillOverprint; // fill overprint GBool strokeOverprint; // stroke overprint + 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 @@ -1180,6 +1217,7 @@ private: 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 diff --git a/Build/source/libs/xpdf/xpdf/GlobalParams.cc b/Build/source/libs/xpdf/xpdf/GlobalParams.cc index 7d4013818e4..2b07a1964fd 100644 --- a/Build/source/libs/xpdf/xpdf/GlobalParams.cc +++ b/Build/source/libs/xpdf/xpdf/GlobalParams.cc @@ -43,6 +43,10 @@ #endif #include "GlobalParams.h" +#ifdef WIN32 +# define strcasecmp stricmp +#endif + #if MULTITHREADED # define lockGlobalParams gLockMutex(&mutex) # define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex) @@ -153,6 +157,251 @@ DisplayFontParam::~DisplayFontParam() { } } +#ifdef WIN32 + +//------------------------------------------------------------------------ +// WinFontInfo +//------------------------------------------------------------------------ + +class WinFontInfo: public DisplayFontParam { +public: + + GBool bold, italic; + + static WinFontInfo *make(GString *nameA, GBool boldA, GBool italicA, + HKEY regKey, char *winFontDir); + WinFontInfo(GString *nameA, GBool boldA, GBool italicA, + GString *fileNameA); + virtual ~WinFontInfo(); + GBool equals(WinFontInfo *fi); +}; + +WinFontInfo *WinFontInfo::make(GString *nameA, GBool boldA, GBool italicA, + HKEY regKey, char *winFontDir) { + GString *regName; + GString *fileNameA; + char buf[MAX_PATH]; + DWORD n; + char c; + int i; + + //----- find the font file + fileNameA = NULL; + regName = nameA->copy(); + if (boldA) { + regName->append(" Bold"); + } + if (italicA) { + regName->append(" Italic"); + } + regName->append(" (TrueType)"); + n = sizeof(buf); + if (RegQueryValueEx(regKey, regName->getCString(), NULL, NULL, + (LPBYTE)buf, &n) == ERROR_SUCCESS) { + fileNameA = new GString(winFontDir); + fileNameA->append('\\')->append(buf); + } + delete regName; + if (!fileNameA) { + delete nameA; + return NULL; + } + + //----- normalize the font name + i = 0; + while (i < nameA->getLength()) { + c = nameA->getChar(i); + if (c == ' ' || c == ',' || c == '-') { + nameA->del(i); + } else { + ++i; + } + } + + return new WinFontInfo(nameA, boldA, italicA, fileNameA); +} + +WinFontInfo::WinFontInfo(GString *nameA, GBool boldA, GBool italicA, + GString *fileNameA): + DisplayFontParam(nameA, displayFontTT) +{ + bold = boldA; + italic = italicA; + tt.fileName = fileNameA; +} + +WinFontInfo::~WinFontInfo() { +} + +GBool WinFontInfo::equals(WinFontInfo *fi) { + return !name->cmp(fi->name) && bold == fi->bold && italic == fi->italic; +} + +//------------------------------------------------------------------------ +// WinFontList +//------------------------------------------------------------------------ + +class WinFontList { +public: + + WinFontList(char *winFontDirA); + ~WinFontList(); + WinFontInfo *find(GString *font); + +private: + + void add(WinFontInfo *fi); + static int CALLBACK enumFunc1(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data); + static int CALLBACK enumFunc2(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data); + + GList *fonts; // [WinFontInfo] + HDC dc; // (only used during enumeration) + HKEY regKey; // (only used during enumeration) + char *winFontDir; // (only used during enumeration) +}; + +WinFontList::WinFontList(char *winFontDirA) { + OSVERSIONINFO version; + char *path; + + fonts = new GList(); + dc = GetDC(NULL); + winFontDir = winFontDirA; + 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) { + EnumFonts(dc, NULL, &WinFontList::enumFunc1, (LPARAM)this); + RegCloseKey(regKey); + } + ReleaseDC(NULL, dc); +} + +WinFontList::~WinFontList() { + deleteGList(fonts, WinFontInfo); +} + +void WinFontList::add(WinFontInfo *fi) { + int i; + + for (i = 0; i < fonts->getLength(); ++i) { + if (((WinFontInfo *)fonts->get(i))->equals(fi)) { + delete fi; + return; + } + } + fonts->append(fi); +} + +WinFontInfo *WinFontList::find(GString *font) { + GString *name; + GBool bold, italic; + WinFontInfo *fi; + char c; + int n, i; + + name = font->copy(); + + // remove space, comma, dash chars + i = 0; + while (i < name->getLength()) { + c = name->getChar(i); + if (c == ' ' || c == ',' || c == '-') { + name->del(i); + } else { + ++i; + } + } + n = name->getLength(); + + // remove trailing "MT" (Foo-MT, Foo-BoldMT, etc.) + if (!strcmp(name->getCString() + n - 2, "MT")) { + name->del(n - 2, 2); + n -= 2; + } + + // look for "Italic" + if (!strcmp(name->getCString() + n - 6, "Italic")) { + name->del(n - 6, 6); + italic = gTrue; + n -= 6; + } else { + italic = gFalse; + } + + // look for "Bold" + if (!strcmp(name->getCString() + n - 4, "Bold")) { + name->del(n - 4, 4); + bold = gTrue; + n -= 4; + } else { + bold = gFalse; + } + + // remove trailing "MT" (FooMT-Bold, etc.) + if (!strcmp(name->getCString() + n - 2, "MT")) { + name->del(n - 2, 2); + n -= 2; + } + + // remove trailing "PS" + if (!strcmp(name->getCString() + n - 2, "PS")) { + name->del(n - 2, 2); + n -= 2; + } + + // search for the font + fi = NULL; + for (i = 0; i < fonts->getLength(); ++i) { + fi = (WinFontInfo *)fonts->get(i); + if (!fi->name->cmp(name) && fi->bold == bold && fi->italic == italic) { + break; + } + fi = NULL; + } + + delete name; + return fi; +} + +int CALLBACK WinFontList::enumFunc1(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data) { + WinFontList *fl = (WinFontList *)data; + + EnumFonts(fl->dc, font->lfFaceName, &WinFontList::enumFunc2, (LPARAM)fl); + return 1; +} + +int CALLBACK WinFontList::enumFunc2(CONST LOGFONT *font, + CONST TEXTMETRIC *metrics, + DWORD type, LPARAM data) { + WinFontList *fl = (WinFontList *)data; + WinFontInfo *fi; + + if (type & TRUETYPE_FONTTYPE) { + if ((fi = WinFontInfo::make(new GString(font->lfFaceName), + font->lfWeight >= 600, + font->lfItalic ? gTrue : gFalse, + fl->regKey, fl->winFontDir))) { + fl->add(fi); + } + } + return 1; +} + +#endif // WIN32 + //------------------------------------------------------------------------ // PSFontParam //------------------------------------------------------------------------ @@ -173,6 +422,41 @@ PSFontParam::~PSFontParam() { } } +#ifndef PDF_PARSER_ONLY +//------------------------------------------------------------------------ +// KeyBinding +//------------------------------------------------------------------------ + +KeyBinding::KeyBinding(int codeA, int modsA, int contextA, char *cmd0) { + code = codeA; + mods = modsA; + context = contextA; + cmds = new GList(); + cmds->append(new GString(cmd0)); +} + +KeyBinding::KeyBinding(int codeA, int modsA, int contextA, + char *cmd0, 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); +} +#endif + #ifdef ENABLE_PLUGINS //------------------------------------------------------------------------ // Plugin @@ -525,6 +809,7 @@ GlobalParams::GlobalParams(char *cfgFileName) { psEmbedTrueType = gTrue; psEmbedCIDPostScript = gTrue; psEmbedCIDTrueType = gTrue; + psPreload = gFalse; psOPI = gFalse; psASCIIHex = gFalse; textEncoding = new GString("Latin1"); @@ -543,9 +828,21 @@ GlobalParams::GlobalParams(char *cfgFileName) { enableT1lib = gTrue; enableFreeType = gTrue; antialias = gTrue; + vectorAntialias = gTrue; + strokeAdjust = gTrue; + screenType = screenUnset; + screenSize = -1; + screenDotRadius = -1; + screenGamma = 1.0; + screenBlackThreshold = 0.0; + screenWhiteThreshold = 1.0; urlCommand = NULL; movieCommand = NULL; mapNumericCharNames = gTrue; + mapUnknownCharNames = gFalse; +#ifndef PDF_PARSER_ONLY + createDefaultKeyBindings(); +#endif printCommands = gFalse; errQuiet = gFalse; @@ -555,6 +852,10 @@ GlobalParams::GlobalParams(char *cfgFileName) { unicodeMapCache = new UnicodeMapCache(); cMapCache = new CMapCache(); +#ifdef WIN32 + winFontList = NULL; +#endif + #ifdef ENABLE_PLUGINS plugins = new GList(); securityHandlers = new GList(); @@ -616,180 +917,342 @@ GlobalParams::GlobalParams(char *cfgFileName) { } } if (f) { +#ifndef PDF_PARSER_ONLY parseFile(fileName, f); +#endif delete fileName; fclose(f); } } +#ifndef PDF_PARSER_ONLY +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; - GList *tokens; - GString *cmd, *incFile; - char *p1, *p2; char buf[512]; - FILE *f2; line = 1; while (getLine(buf, sizeof(buf) - 1, f)) { + parseLine(buf, fileName, line); + ++line; + } +} - // 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, p2 - p1)); - p1 = *p2 ? p2 + 1 : p2; - } +void GlobalParams::parseLine(char *buf, GString *fileName, int line) { + GList *tokens; + GString *cmd, *incFile; + char *p1, *p2; + FILE *f2; - 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 = fopen(incFile->getCString(), "r"))) { - parseFile(incFile, f2); - fclose(f2); - } else { - error(-1, "Couldn't find included config file: '%s' (%s:%d)", - incFile->getCString(), fileName->getCString(), line); - } + // 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, 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 = fopen(incFile->getCString(), "r"))) { + parseFile(incFile, f2); + fclose(f2); } else { - error(-1, "Bad 'include' config file command (%s:%d)", - fileName->getCString(), line); + error(-1, "Couldn't find included config file: '%s' (%s:%d)", + incFile->getCString(), fileName->getCString(), 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("displayFontT1")) { - parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); - } else if (!cmd->cmp("displayFontTT")) { - parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontT1")) { - parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontT1, fileName, line); - } else if (!cmd->cmp("displayCIDFontT1")) { - parseDisplayFont(tokens, displayCIDFonts, - displayFontT1, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontTT")) { - parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontTT, fileName, line); - } else if (!cmd->cmp("displayCIDFontTT")) { - parseDisplayFont(tokens, displayCIDFonts, - displayFontTT, fileName, line); - } else if (!cmd->cmp("psFile")) { - parsePSFile(tokens, fileName, line); - } else if (!cmd->cmp("psFont")) { - parsePSFont(tokens, fileName, line); - } else if (!cmd->cmp("psNamedFont16")) { - parsePSFont16("psNamedFont16", psNamedFonts16, - tokens, fileName, line); - } else if (!cmd->cmp("psFont16")) { - parsePSFont16("psFont16", psFonts16, 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("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("psOPI")) { - parseYesNo("psOPI", &psOPI, tokens, fileName, line); - } else if (!cmd->cmp("psASCIIHex")) { - parseYesNo("psASCIIHex", &psASCIIHex, 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("fontDir")) { - parseFontDir(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("antialias")) { - parseYesNo("antialias", &antialias, 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("printCommands")) { - parseYesNo("printCommands", &printCommands, tokens, fileName, line); - } else if (!cmd->cmp("errQuiet")) { - parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); } else { - error(-1, "Unknown config file command '%s' (%s:%d)", - cmd->getCString(), fileName->getCString(), line); - if (!cmd->cmp("displayFontX") || - !cmd->cmp("displayNamedCIDFontX") || - !cmd->cmp("displayCIDFontX")) { - error(-1, "-- Xpdf no longer supports X fonts"); - } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { - error(-1, "-- The t1libControl and freetypeControl options have been replaced"); - error(-1, " by the enableT1lib, enableFreeType, and antialias options"); - } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { - error(-1, "-- the config file format has changed since Xpdf 0.9x"); - } + error(-1, "Bad 'include' config file command (%s:%d)", + fileName->getCString(), 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("displayFontT1")) { + parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); + } else if (!cmd->cmp("displayFontTT")) { + parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontT1")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayCIDFontT1")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontT1, fileName, line); + } else if (!cmd->cmp("displayNamedCIDFontTT")) { + parseDisplayFont(tokens, displayNamedCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("displayCIDFontTT")) { + parseDisplayFont(tokens, displayCIDFonts, + displayFontTT, fileName, line); + } else if (!cmd->cmp("psFile")) { + parsePSFile(tokens, fileName, line); + } else if (!cmd->cmp("psFont")) { + parsePSFont(tokens, fileName, line); + } else if (!cmd->cmp("psNamedFont16")) { + parsePSFont16("psNamedFont16", psNamedFonts16, + tokens, fileName, line); + } else if (!cmd->cmp("psFont16")) { + parsePSFont16("psFont16", psFonts16, 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("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("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("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("fontDir")) { + parseFontDir(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("antialias")) { + parseYesNo("antialias", &antialias, tokens, fileName, line); + } else if (!cmd->cmp("vectorAntialias")) { + parseYesNo("vectorAntialias", &vectorAntialias, + 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("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(-1, "Unknown config file command '%s' (%s:%d)", + cmd->getCString(), fileName->getCString(), line); + if (!cmd->cmp("displayFontX") || + !cmd->cmp("displayNamedCIDFontX") || + !cmd->cmp("displayCIDFontX")) { + error(-1, "-- Xpdf no longer supports X fonts"); + } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { + error(-1, "-- The t1libControl and freetypeControl options have been replaced"); + error(-1, " by the enableT1lib, enableFreeType, and antialias options"); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "-- the config file format has changed since Xpdf 0.9x"); } } - - deleteGList(tokens, GString); - ++line; } + + deleteGList(tokens, GString); } +#endif void GlobalParams::parseNameToUnicode(GList *tokens, GString *fileName, int line) { @@ -1112,6 +1575,216 @@ void GlobalParams::parseInitialZoom(GList *tokens, initialZoom = ((GString *)tokens->get(1))->copy(); } +void GlobalParams::parseScreenType(GList *tokens, GString *fileName, + int line) { + GString *tok; + + if (tokens->getLength() != 2) { + error(-1, "Bad 'screenType' config file command (%s:%d)", + fileName->getCString(), 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(-1, "Bad 'screenType' config file command (%s:%d)", + fileName->getCString(), line); + } +} + +#ifndef PDF_PARSER_ONLY +void GlobalParams::parseBind(GList *tokens, GString *fileName, int line) { + KeyBinding *binding; + GList *cmds; + int code, mods, context, i; + + if (tokens->getLength() < 4) { + error(-1, "Bad 'bind' config file command (%s:%d)", + fileName->getCString(), 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(-1, "Bad 'unbind' config file command (%s:%d)", + fileName->getCString(), 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, + char *cmdName, + GList *tokens, GString *fileName, int line) { + char *p0; + + *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] >= '1' && p0[10] <= '7' && !p0[11]) { + *code = xpdfKeyCodeMousePress1 + (p0[10] - '1'); + } else if (!strncmp(p0, "mouseRelease", 12) && + p0[12] >= '1' && p0[12] <= '7' && !p0[13]) { + *code = xpdfKeyCodeMouseRelease1 + (p0[12] - '1'); + } else if (*p0 >= 0x20 && *p0 <= 0x7e && !p0[1]) { + *code = (int)*p0; + } else { + error(-1, "Bad key/modifier in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), 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(-1, "Bad context in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return gFalse; + } + if (!*p0) { + break; + } + if (*p0 != ',') { + error(-1, "Bad context in '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return gFalse; + } + ++p0; + } + } + + return gTrue; +} +#endif + void GlobalParams::parseCommand(char *cmdName, GString **val, GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { @@ -1152,6 +1825,69 @@ GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { return gTrue; } +void GlobalParams::parseInteger(char *cmdName, int *val, + GList *tokens, GString *fileName, int line) { + GString *tok; + int i; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (tok->getLength() == 0) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), 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(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + } + *val = atoi(tok->getCString()); +} + +void GlobalParams::parseFloat(char *cmdName, double *val, + GList *tokens, GString *fileName, int line) { + GString *tok; + int i; + + if (tokens->getLength() != 2) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + tok = (GString *)tokens->get(1); + if (tok->getLength() == 0) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), 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(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + return; + } + } + *val = atof(tok->getCString()); +} + GlobalParams::~GlobalParams() { GHashIter *iter; GString *key; @@ -1171,6 +1907,11 @@ GlobalParams::~GlobalParams() { deleteGHash(displayFonts, DisplayFontParam); deleteGHash(displayCIDFonts, DisplayFontParam); deleteGHash(displayNamedCIDFonts, DisplayFontParam); +#ifdef WIN32 + if (winFontList) { + delete winFontList; + } +#endif if (psFile) { delete psFile; } @@ -1186,6 +1927,9 @@ GlobalParams::~GlobalParams() { if (movieCommand) { delete movieCommand; } +#ifndef PDF_PARSER_ONLY + deleteGList(keyBindings, KeyBinding); +#endif cMapDirs->startIter(&iter); while (cMapDirs->getNext(&iter, &key, (void **)&list)) { @@ -1241,7 +1985,7 @@ void GlobalParams::setupBaseFonts(char *dir) { if ((SHGetSpecialFolderPathFunc = (BOOL (__stdcall *)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate)) - GetProcAddress(shell32Lib, "SHGetSpecialFolderPath"))) { + GetProcAddress(shell32Lib, "SHGetSpecialFolderPathA"))) { if (!(*SHGetSpecialFolderPathFunc)(NULL, winFontDir, CSIDL_FONTS, FALSE)) { winFontDir[0] = '\0'; @@ -1317,6 +2061,12 @@ void GlobalParams::setupBaseFonts(char *dir) { dfp->t1.fileName = fileName; globalParams->addDisplayFont(dfp); } + +#ifdef WIN32 + if (winFontDir[0]) { + winFontList = new WinFontList(winFontDir); + } +#endif } //------------------------------------------------------------------------ @@ -1419,6 +2169,11 @@ DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) { lockGlobalParams; dfp = (DisplayFontParam *)displayFonts->lookup(fontName); +#ifdef WIN32 + if (!dfp && winFontList) { + dfp = winFontList->find(fontName); + } +#endif unlockGlobalParams; return dfp; } @@ -1602,6 +2357,15 @@ GBool GlobalParams::getPSEmbedCIDTrueType() { return e; } +GBool GlobalParams::getPSPreload() { + GBool preload; + + lockGlobalParams; + preload = psPreload; + unlockGlobalParams; + return preload; +} + GBool GlobalParams::getPSOPI() { GBool opi; @@ -1726,6 +2490,78 @@ GBool GlobalParams::getAntialias() { return f; } +GBool GlobalParams::getVectorAntialias() { + GBool f; + + lockGlobalParams; + f = vectorAntialias; + 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; +} + GBool GlobalParams::getMapNumericCharNames() { GBool map; @@ -1735,6 +2571,43 @@ GBool GlobalParams::getMapNumericCharNames() { return map; } +GBool GlobalParams::getMapUnknownCharNames() { + GBool map; + + lockGlobalParams; + map = mapUnknownCharNames; + unlockGlobalParams; + return map; +} + +#ifndef PDF_PARSER_ONLY +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; +} +#endif + GBool GlobalParams::getPrintCommands() { GBool p; @@ -1745,12 +2618,9 @@ GBool GlobalParams::getPrintCommands() { } GBool GlobalParams::getErrQuiet() { - GBool q; - - lockGlobalParams; - q = errQuiet; - unlockGlobalParams; - return q; + // no locking -- this function may get called from inside a locked + // section + return errQuiet; } CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) { @@ -1960,6 +2830,12 @@ void GlobalParams::setPSEmbedCIDTrueType(GBool embed) { unlockGlobalParams; } +void GlobalParams::setPSPreload(GBool preload) { + lockGlobalParams; + psPreload = preload; + unlockGlobalParams; +} + void GlobalParams::setPSOPI(GBool opi) { lockGlobalParams; psOPI = opi; @@ -2048,12 +2924,63 @@ GBool GlobalParams::setAntialias(char *s) { 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; @@ -2082,7 +3009,7 @@ XpdfSecurityHandler *GlobalParams::getSecurityHandler(char *name) { lockGlobalParams; for (i = 0; i < securityHandlers->getLength(); ++i) { hdlr = (XpdfSecurityHandler *)securityHandlers->get(i); - if (!stricmp(hdlr->name, name)) { + if (!strcasecmp(hdlr->name, name)) { unlockGlobalParams; return hdlr; } diff --git a/Build/source/libs/xpdf/xpdf/GlobalParams.h b/Build/source/libs/xpdf/xpdf/GlobalParams.h index 99f78a76746..566d43ca7e7 100644 --- a/Build/source/libs/xpdf/xpdf/GlobalParams.h +++ b/Build/source/libs/xpdf/xpdf/GlobalParams.h @@ -35,6 +35,9 @@ class CMap; class CMapCache; struct XpdfSecurityHandler; class GlobalParams; +#ifdef WIN32 +class WinFontList; +#endif //------------------------------------------------------------------------ @@ -69,7 +72,7 @@ public: }; DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); - ~DisplayFontParam(); + virtual ~DisplayFontParam(); }; //------------------------------------------------------------------------ @@ -111,6 +114,83 @@ enum EndOfLineKind { //------------------------------------------------------------------------ +enum ScreenType { + screenUnset, + screenDispersed, + screenClustered, + screenStochasticClustered +}; + +//------------------------------------------------------------------------ + +#ifndef PDF_PARSER_ONLY +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, char *cmd0); + KeyBinding(int codeA, int modsA, int contextA, char *cmd0, 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 xpdfKeyCodeMouseRelease1 0x2101 +#define xpdfKeyCodeMouseRelease2 0x2102 +#define xpdfKeyCodeMouseRelease3 0x2103 +#define xpdfKeyCodeMouseRelease4 0x2104 +#define xpdfKeyCodeMouseRelease5 0x2105 +#define xpdfKeyCodeMouseRelease6 0x2106 +#define xpdfKeyCodeMouseRelease7 0x2107 +#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) +#endif + +//------------------------------------------------------------------------ + class GlobalParams { public: @@ -126,6 +206,10 @@ public: void setBaseDir(char *dir); void setupBaseFonts(char *dir); +#ifndef PDF_PARSER_ONLY + void parseLine(char *buf, GString *fileName, int line); +#endif + //----- accessors CharCode getMacRomanCharCode(char *charName); @@ -154,6 +238,7 @@ public: GBool getPSEmbedTrueType(); GBool getPSEmbedCIDPostScript(); GBool getPSEmbedCIDTrueType(); + GBool getPSPreload(); GBool getPSOPI(); GBool getPSASCIIHex(); GString *getTextEncodingName(); @@ -166,9 +251,21 @@ public: GBool getEnableT1lib(); GBool getEnableFreeType(); GBool getAntialias(); + GBool getVectorAntialias(); + GBool getStrokeAdjust(); + ScreenType getScreenType(); + int getScreenSize(); + int getScreenDotRadius(); + double getScreenGamma(); + double getScreenBlackThreshold(); + double getScreenWhiteThreshold(); GString *getURLCommand() { return urlCommand; } GString *getMovieCommand() { return movieCommand; } GBool getMapNumericCharNames(); + GBool getMapUnknownCharNames(); +#ifndef PDF_PARSER_ONLY + GList *getKeyBinding(int code, int mods, int context); +#endif GBool getPrintCommands(); GBool getErrQuiet(); @@ -196,6 +293,7 @@ public: void setPSEmbedTrueType(GBool embed); void setPSEmbedCIDPostScript(GBool embed); void setPSEmbedCIDTrueType(GBool embed); + void setPSPreload(GBool preload); void setPSOPI(GBool opi); void setPSASCIIHex(GBool hex); void setTextEncoding(char *encodingName); @@ -207,7 +305,15 @@ public: 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); @@ -218,6 +324,9 @@ public: private: +#ifndef PDF_PARSER_ONLY + void createDefaultKeyBindings(); +#endif void parseFile(GString *fileName, FILE *f); void parseNameToUnicode(GList *tokens, GString *fileName, int line); void parseCIDToUnicode(GList *tokens, GString *fileName, int line); @@ -239,11 +348,24 @@ private: void parseTextEOL(GList *tokens, GString *fileName, int line); void parseFontDir(GList *tokens, GString *fileName, int line); void parseInitialZoom(GList *tokens, GString *fileName, int line); + void parseScreenType(GList *tokens, GString *fileName, int line); +#ifndef PDF_PARSER_ONLY + 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, + char *cmdName, + GList *tokens, GString *fileName, int line); +#endif void parseCommand(char *cmdName, GString **val, GList *tokens, GString *fileName, int line); void parseYesNo(char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line); GBool parseYesNo2(char *token, GBool *flag); + void parseInteger(char *cmdName, int *val, + GList *tokens, GString *fileName, int line); + void parseFloat(char *cmdName, double *val, + GList *tokens, GString *fileName, int line); UnicodeMap *getUnicodeMap2(GString *encodingName); #ifdef ENABLE_PLUGINS GBool loadPlugin(char *type, char *name); @@ -273,6 +395,9 @@ private: GList *toUnicodeDirs; // list of ToUnicode CMap dirs [GString] GHash *displayFonts; // display font info, indexed by font name // [DisplayFontParam] +#ifdef WIN32 + WinFontList *winFontList; // system TrueType fonts +#endif GHash *displayCIDFonts; // display CID font info, indexed by // collection [DisplayFontParam] GHash *displayNamedCIDFonts; // display CID font info, indexed by @@ -298,6 +423,8 @@ private: GBool psEmbedTrueType; // embed TrueType fonts? GBool psEmbedCIDPostScript; // embed CID PostScript fonts? GBool psEmbedCIDTrueType; // embed CID TrueType fonts? + GBool psPreload; // preload PostScript images and forms into + // memory GBool psOPI; // generate PostScript OPI comments? GBool psASCIIHex; // use ASCIIHex instead of ASCII85? GString *textEncoding; // encoding (unicodeMap) to use for text @@ -311,10 +438,22 @@ private: GBool continuousView; // continuous view mode GBool enableT1lib; // t1lib enable flag GBool enableFreeType; // FreeType enable flag - GBool antialias; // anti-aliasing enable flag + GBool antialias; // font anti-aliasing enable flag + GBool vectorAntialias; // vector anti-aliasing enable flag + 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 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? +#ifndef PDF_PARSER_ONLY + GList *keyBindings; // key & mouse button bindings [KeyBinding] +#endif GBool printCommands; // print the drawing commands GBool errQuiet; // suppress error messages? diff --git a/Build/source/libs/xpdf/xpdf/JBIG2Stream.cc b/Build/source/libs/xpdf/xpdf/JBIG2Stream.cc index 5e263079d3a..a4f1b6eacdc 100644 --- a/Build/source/libs/xpdf/xpdf/JBIG2Stream.cc +++ b/Build/source/libs/xpdf/xpdf/JBIG2Stream.cc @@ -1099,7 +1099,7 @@ JBIG2CodeTable::~JBIG2CodeTable() { // JBIG2Stream //------------------------------------------------------------------------ -JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream): +JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStreamA): FilterStream(strA) { pageBitmap = NULL; @@ -1124,22 +1124,15 @@ JBIG2Stream::JBIG2Stream(Stream *strA, Object *globalsStream): huffDecoder = new JBIG2HuffmanDecoder(); mmrDecoder = new JBIG2MMRDecoder(); - segments = globalSegments = new GList(); - if (globalsStream->isStream()) { - curStr = globalsStream->getStream(); - curStr->reset(); - arithDecoder->setStream(curStr); - huffDecoder->setStream(curStr); - mmrDecoder->setStream(curStr); - readSegments(); - } - - segments = NULL; + globalsStreamA->copy(&globalsStream); + segments = globalSegments = NULL; curStr = NULL; dataPtr = dataEnd = NULL; } JBIG2Stream::~JBIG2Stream() { + close(); + globalsStream.free(); delete arithDecoder; delete genericRegionStats; delete refinementRegionStats; @@ -1159,28 +1152,25 @@ JBIG2Stream::~JBIG2Stream() { delete iaidStats; delete huffDecoder; delete mmrDecoder; - if (pageBitmap) { - delete pageBitmap; - } - if (segments) { - deleteGList(segments, JBIG2Segment); - } - if (globalSegments) { - deleteGList(globalSegments, JBIG2Segment); - } delete str; } void JBIG2Stream::reset() { - if (pageBitmap) { - delete pageBitmap; - pageBitmap = NULL; - } - if (segments) { - deleteGList(segments, JBIG2Segment); + // 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(); } - segments = new GList(); + // read the main stream + segments = new GList(); curStr = str; curStr->reset(); arithDecoder->setStream(curStr); @@ -1192,10 +1182,27 @@ void JBIG2Stream::reset() { dataPtr = pageBitmap->getDataPtr(); dataEnd = dataPtr + pageBitmap->getDataSize(); } else { - dataPtr = NULL; + 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; @@ -2352,9 +2359,9 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, skipBitmap = new JBIG2Bitmap(0, gridW, gridH); skipBitmap->clearToZero(); for (m = 0; m < gridH; ++m) { - xx = gridX + m * stepY; - yy = gridY + m * stepX; 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); @@ -2401,6 +2408,9 @@ void JBIG2Stream::readHalftoneRegionSeg(Guint segNum, GBool imm, } gfree(grayImg); + if (skipBitmap) { + delete skipBitmap; + } // combine the region bitmap into the page bitmap if (imm) { @@ -3331,7 +3341,7 @@ void JBIG2Stream::resetIntStats(int symCodeLen) { iardwStats->reset(); iardhStats->reset(); iariStats->reset(); - if (iaidStats->getContextSize() == symCodeLen + 1) { + if (iaidStats->getContextSize() == 1 << (symCodeLen + 1)) { iaidStats->reset(); } else { delete iaidStats; diff --git a/Build/source/libs/xpdf/xpdf/JBIG2Stream.h b/Build/source/libs/xpdf/xpdf/JBIG2Stream.h index 44e09db2891..210d927a7cf 100644 --- a/Build/source/libs/xpdf/xpdf/JBIG2Stream.h +++ b/Build/source/libs/xpdf/xpdf/JBIG2Stream.h @@ -33,10 +33,11 @@ class JBIG2MMRDecoder; class JBIG2Stream: public FilterStream { public: - JBIG2Stream(Stream *strA, Object *globalsStream); + 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 GString *getPSFilter(int psLevel, char *indent); @@ -109,6 +110,7 @@ private: GBool readULong(Guint *x); GBool readLong(int *x); + Object globalsStream; Guint pageW, pageH, curPageH; Guint pageDefPixel; JBIG2Bitmap *pageBitmap; diff --git a/Build/source/libs/xpdf/xpdf/JPXStream.cc b/Build/source/libs/xpdf/xpdf/JPXStream.cc index d483cd4bf92..7107854912d 100644 --- a/Build/source/libs/xpdf/xpdf/JPXStream.cc +++ b/Build/source/libs/xpdf/xpdf/JPXStream.cc @@ -177,6 +177,59 @@ static Guint signContext[5][5][2] = { //------------------------------------------------------------------------ +#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) { @@ -196,6 +249,24 @@ JPXStream::JPXStream(Stream *strA): } JPXStream::~JPXStream() { + close(); + delete str; +} + +void JPXStream::reset() { + str->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; @@ -205,19 +276,23 @@ JPXStream::~JPXStream() { 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) { @@ -267,21 +342,9 @@ JPXStream::~JPXStream() { } } gfree(img.tiles); + img.tiles = NULL; } - delete str; -} - -void JPXStream::reset() { - str->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; + FilterStream::close(); } int JPXStream::getChar() { @@ -394,8 +457,10 @@ void JPXStream::getImageParams(int *bitsPerComponent, } 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) && @@ -407,6 +472,7 @@ void JPXStream::getImageParams(int *bitsPerComponent, haveBPC = gTrue; } } else if (boxType == 0x636F6C72) { // color specification + cover(2); if (readByte(&csMeth) && readByte(&csPrec1) && readByte(&dummy2)) { @@ -440,11 +506,13 @@ void JPXStream::getImageParams(int *bitsPerComponent, } } } else if (boxType == 0x6A703263) { // codestream + cover(3); if (!(haveBPC && haveCSMode)) { getImageParams2(bitsPerComponent, csMode); } break; } else { + cover(4); for (i = 0; i < dataLen; ++i) { str->getChar(); } @@ -462,6 +530,7 @@ void JPXStream::getImageParams2(int *bitsPerComponent, while (readMarkerHdr(&segType, &segLen)) { if (segType == 0x51) { // SIZ - image and tile size + cover(5); if (readUWord(&dummy) && readULong(&dummy) && readULong(&dummy) && @@ -485,6 +554,7 @@ void JPXStream::getImageParams2(int *bitsPerComponent, } break; } else { + cover(6); if (segLen > 2) { for (i = 0; i < segLen - 2; ++i) { str->getChar(); @@ -505,6 +575,7 @@ GBool JPXStream::readBoxes() { // wrapper) -- this appears to be a violation of the PDF spec, but // Acrobat allows it if (str->lookChar() == 0xff) { + cover(7); error(getPos(), "Naked JPEG 2000 codestream, missing JP2/JPX wrapper"); readCodestream(0); nComps = img.nComps; @@ -525,8 +596,10 @@ GBool JPXStream::readBoxes() { // 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) || @@ -548,6 +621,7 @@ GBool JPXStream::readBoxes() { haveImgHdr = gTrue; break; case 0x62706363: // bits per component + cover(10); if (!haveImgHdr) { error(getPos(), "Found bits per component box before image header box in JPX stream"); return gFalse; @@ -564,11 +638,13 @@ GBool JPXStream::readBoxes() { } 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(getPos(), "Unexpected EOF in JPX stream"); @@ -597,6 +673,7 @@ GBool JPXStream::readBoxes() { 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)); @@ -612,6 +689,7 @@ GBool JPXStream::readBoxes() { haveCompMap = gTrue; break; case 0x63646566: // channel definition + cover(14); if (!readUWord(&channelDefn.nChannels)) { error(getPos(), "Unexpected EOF in JPX stream"); return gFalse; @@ -633,6 +711,7 @@ GBool JPXStream::readBoxes() { haveChannelDefn = gTrue; break; case 0x6A703263: // contiguous codestream + cover(15); if (!bpc) { error(getPos(), "JPX stream is missing the image header box"); } @@ -644,6 +723,7 @@ GBool JPXStream::readBoxes() { } break; default: + cover(16); for (i = 0; i < dataLen; ++i) { if (str->getChar() == EOF) { error(getPos(), "Unexpected EOF in JPX stream"); @@ -670,6 +750,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { } switch (newCS.meth) { case 1: // enumerated colorspace + cover(17); if (!readULong(&csEnum)) { goto err; } @@ -712,6 +793,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { } } 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; @@ -758,6 +840,7 @@ GBool JPXStream::readColorSpecBox(Guint dataLen) { 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 (str->getChar() == EOF) { goto err; @@ -784,7 +867,7 @@ GBool JPXStream::readCodestream(Guint len) { int segType; GBool haveSIZ, haveCOD, haveQCD, haveSOT; Guint precinctSize, style; - Guint segLen, capabilities, nTiles, comp, i, j, r; + Guint segLen, capabilities, comp, i, j, r; //----- main header haveSIZ = haveCOD = haveQCD = haveSOT = gFalse; @@ -796,8 +879,10 @@ GBool JPXStream::readCodestream(Guint len) { switch (segType) { case 0x4f: // SOC - start of codestream // marker only + cover(19); break; case 0x51: // SIZ - image and tile size + cover(20); if (!readUWord(&capabilities) || !readULong(&img.xSize) || !readULong(&img.ySize) || @@ -819,14 +904,14 @@ GBool JPXStream::readCodestream(Guint len) { / img.xTileSize; img.nYTiles = (img.ySize - img.yTileOffset + img.yTileSize - 1) / img.yTileSize; - nTiles = img.nXTiles * img.nYTiles; // check for overflow before allocating memory if (img.nXTiles <= 0 || img.nYTiles <= 0 || img.nXTiles >= INT_MAX / img.nYTiles) { error(getPos(), "Bad tile count in JPX SIZ marker segment"); return gFalse; } - img.tiles = (JPXTile *)gmallocn(nTiles, sizeof(JPXTile)); + img.tiles = (JPXTile *)gmallocn(img.nXTiles * img.nYTiles, + sizeof(JPXTile)); for (i = 0; i < img.nXTiles * img.nYTiles; ++i) { img.tiles[i].tileComps = (JPXTileComp *)gmallocn(img.nComps, sizeof(JPXTileComp)); @@ -855,6 +940,7 @@ GBool JPXStream::readCodestream(Guint len) { haveSIZ = gTrue; break; case 0x52: // COD - coding style default + cover(21); if (!readUByte(&img.tiles[0].tileComps[0].style) || !readUByte(&img.tiles[0].progOrder) || !readUWord(&img.tiles[0].nLayers) || @@ -901,6 +987,7 @@ GBool JPXStream::readCodestream(Guint len) { } 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(getPos(), "Error in JPX COD marker segment"); return gFalse; @@ -929,6 +1016,7 @@ GBool JPXStream::readCodestream(Guint len) { haveCOD = gTrue; break; case 0x53: // COC - coding style component + cover(22); if (!haveCOD) { error(getPos(), "JPX COC marker segment before COD segment"); return gFalse; @@ -998,6 +1086,7 @@ GBool JPXStream::readCodestream(Guint len) { } break; case 0x5c: // QCD - quantization default + cover(23); if (!readUByte(&img.tiles[0].tileComps[0].quantStyle)) { error(getPos(), "Error in JPX QCD marker segment"); return gFalse; @@ -1061,6 +1150,7 @@ GBool JPXStream::readCodestream(Guint len) { haveQCD = gTrue; break; case 0x5d: // QCC - quantization component + cover(24); if (!haveQCD) { error(getPos(), "JPX QCC marker segment before QCD segment"); return gFalse; @@ -1128,6 +1218,7 @@ GBool JPXStream::readCodestream(Guint len) { } break; case 0x5e: // RGN - region of interest + cover(25); #if 1 //~ ROI is unimplemented fprintf(stderr, "RGN\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1148,6 +1239,7 @@ GBool JPXStream::readCodestream(Guint len) { #endif break; case 0x5f: // POC - progression order change + cover(26); #if 1 //~ progression order changes are unimplemented fprintf(stderr, "POC\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1175,6 +1267,7 @@ GBool JPXStream::readCodestream(Guint len) { #endif break; case 0x60: // PPM - packed packet headers, main header + cover(27); #if 1 //~ packed packet headers are unimplemented fprintf(stderr, "PPM\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1187,6 +1280,7 @@ GBool JPXStream::readCodestream(Guint len) { break; case 0x55: // TLM - tile-part lengths // skipped + cover(28); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX TLM marker segment"); @@ -1196,6 +1290,7 @@ GBool JPXStream::readCodestream(Guint len) { break; case 0x57: // PLM - packet length, main header // skipped + cover(29); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX PLM marker segment"); @@ -1205,6 +1300,7 @@ GBool JPXStream::readCodestream(Guint len) { break; case 0x63: // CRG - component registration // skipped + cover(30); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX CRG marker segment"); @@ -1214,6 +1310,7 @@ GBool JPXStream::readCodestream(Guint len) { break; case 0x64: // COM - comment // skipped + cover(31); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX COM marker segment"); @@ -1222,9 +1319,11 @@ GBool JPXStream::readCodestream(Guint len) { } break; case 0x90: // SOT - start of tile + cover(32); haveSOT = gTrue; break; default: + cover(33); error(getPos(), "Unknown marker segment %02x in JPX stream", segType); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { @@ -1325,6 +1424,7 @@ GBool JPXStream::readTilePart() { 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) || @@ -1392,6 +1492,7 @@ GBool JPXStream::readTilePart() { } break; case 0x53: // COC - coding style component + cover(35); if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || @@ -1433,6 +1534,7 @@ GBool JPXStream::readTilePart() { } break; case 0x5c: // QCD - quantization default + cover(36); if (!readUByte(&img.tiles[tileIdx].tileComps[0].quantStyle)) { error(getPos(), "Error in JPX QCD marker segment"); return gFalse; @@ -1492,6 +1594,7 @@ GBool JPXStream::readTilePart() { } break; case 0x5d: // QCC - quantization component + cover(37); if ((img.nComps > 256 && !readUWord(&comp)) || (img.nComps <= 256 && !readUByte(&comp)) || comp >= img.nComps || @@ -1543,6 +1646,7 @@ GBool JPXStream::readTilePart() { } break; case 0x5e: // RGN - region of interest + cover(38); #if 1 //~ ROI is unimplemented fprintf(stderr, "RGN\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1563,6 +1667,7 @@ GBool JPXStream::readTilePart() { #endif break; case 0x5f: // POC - progression order change + cover(39); #if 1 //~ progression order changes are unimplemented fprintf(stderr, "POC\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1590,6 +1695,7 @@ GBool JPXStream::readTilePart() { #endif break; case 0x61: // PPT - packed packet headers, tile-part hdr + cover(40); #if 1 //~ packed packet headers are unimplemented fprintf(stderr, "PPT\n"); for (i = 0; i < segLen - 2; ++i) { @@ -1601,6 +1707,7 @@ GBool JPXStream::readTilePart() { #endif case 0x58: // PLT - packet length, tile-part header // skipped + cover(41); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX PLT marker segment"); @@ -1610,6 +1717,7 @@ GBool JPXStream::readTilePart() { break; case 0x64: // COM - comment // skipped + cover(42); for (i = 0; i < segLen - 2; ++i) { if (str->getChar() == EOF) { error(getPos(), "Error in JPX COM marker segment"); @@ -1618,9 +1726,11 @@ GBool JPXStream::readTilePart() { } break; case 0x93: // SOD - start of data + cover(43); haveSOD = gTrue; break; default: + cover(44); error(getPos(), "Unknown marker segment %02x in JPX tile-part stream", segType); for (i = 0; i < segLen - 2; ++i) { @@ -1818,6 +1928,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, while (1) { if (tilePartToEOC) { //~ peek for an EOC marker + cover(93); } else if (tilePartLen == 0) { break; } @@ -1828,12 +1939,16 @@ GBool JPXStream::readTilePartData(Guint tileIdx, //----- packet header + // setup + startBitBuf(tilePartLen); + // 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) { @@ -1853,16 +1968,19 @@ GBool JPXStream::readTilePartData(Guint tileIdx, // 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) { @@ -1896,9 +2014,11 @@ GBool JPXStream::readTilePartData(Guint tileIdx, } 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) { @@ -1932,26 +2052,33 @@ GBool JPXStream::readTilePartData(Guint tileIdx, 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; } @@ -1985,8 +2112,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, } } } - tilePartLen -= byteCount; - clearBitBuf(); + tilePartLen = finishBitBuf(); //----- packet data @@ -2011,6 +2137,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, 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) { @@ -2022,6 +2149,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, } break; case 1: // resolution level, layer, component, precinct + cover(59); if (++tile->comp == img.nComps) { tile->comp = 0; if (++tile->layer == tile->nLayers) { @@ -2034,6 +2162,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, 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) { @@ -2046,6 +2175,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, 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) { @@ -2058,6 +2188,7 @@ GBool JPXStream::readTilePartData(Guint tileIdx, 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) { @@ -2090,8 +2221,10 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, Guint i, x, y0, y1, y2; if (cb->arithDecoder) { + cover(63); cb->arithDecoder->restart(cb->dataLen); } else { + cover(64); cb->arithDecoder = new JArithmeticDecoder(); cb->arithDecoder->setStream(str, cb->dataLen); cb->arithDecoder->start(); @@ -2106,6 +2239,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, //----- significance propagation pass case jpxPassSigProp: + cover(65); for (y0 = cb->y0, coeff0 = cb->coeffs; y0 < cb->y1; y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { @@ -2183,6 +2317,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, //----- magnitude refinement pass case jpxPassMagRef: + cover(66); for (y0 = cb->y0, coeff0 = cb->coeffs; y0 < cb->y1; y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { @@ -2244,6 +2379,7 @@ GBool JPXStream::readCodeBlockData(JPXTileComp *tileComp, //----- cleanup pass case jpxPassCleanup: + cover(67); for (y0 = cb->y0, coeff0 = cb->coeffs; y0 < cb->y1; y0 += 4, coeff0 += 4 << tileComp->codeBlockW) { @@ -2405,6 +2541,8 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { Guint nx0, ny0, nx1, ny1; Guint r, cbX, cbY, x, y; + cover(68); + //----- (NL)LL subband (resolution level 0) resLevel = &tileComp->resLevels[0]; @@ -2415,14 +2553,17 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { 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; } @@ -2442,18 +2583,24 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { if (val != 0) { shift2 = shift - (cb->nZeroBitPlanes + coeff->len); if (shift2 > 0) { + cover(94); 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); } if (coeff->flags & jpxCoeffSign) { + cover(99); val = -val; } } @@ -2474,11 +2621,13 @@ void JPXStream::inverseTransform(JPXTileComp *tileComp) { // and inverse transform to get (n-1)LL, which will be stored // in the upper-left corner of the tile-component data array if (r == tileComp->nDecompLevels) { + cover(72); nx0 = tileComp->x0; ny0 = tileComp->y0; nx1 = tileComp->x1; ny1 = tileComp->y1; } else { + cover(73); nx0 = tileComp->resLevels[r+1].x0; ny0 = tileComp->resLevels[r+1].y0; nx1 = tileComp->resLevels[r+1].x1; @@ -2531,18 +2680,22 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, // 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; } @@ -2565,18 +2718,23 @@ void JPXStream::inverseTransformLevel(JPXTileComp *tileComp, if (val != 0) { shift2 = shift - (cb->nZeroBitPlanes + coeff->len); if (shift2 > 0) { + cover(74); 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); } if (coeff->flags & jpxCoeffSign) { + cover(78); val = -val; } } @@ -2613,11 +2771,14 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, //----- special case for length = 1 if (i1 - i0 == 1) { + cover(79); if (i0 & 1) { + cover(104); *data >>= 1; } } else { + cover(80); // choose an offset: this makes even buf[] indexes correspond to // odd values of i, and vice versa @@ -2633,19 +2794,25 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, //----- extend right buf[end] = buf[end - 2]; if (i1 - i0 == 2) { + cover(81); buf[end+1] = buf[offset + 1]; buf[end+2] = buf[offset]; buf[end+3] = buf[offset + 1]; } else { + cover(82); buf[end+1] = buf[end - 3]; if (i1 - i0 == 3) { + cover(105); buf[end+2] = buf[offset + 1]; buf[end+3] = buf[offset + 2]; } else { + cover(106); buf[end+2] = buf[end - 4]; if (i1 - i0 == 4) { + cover(107); buf[end+3] = buf[offset + 1]; } else { + cover(108); buf[end+3] = buf[end - 5]; } } @@ -2656,12 +2823,14 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, buf[offset - 2] = buf[offset + 2]; buf[offset - 3] = buf[offset + 3]; if (offset == 4) { + cover(83); buf[0] = buf[offset + 4]; } //----- 9-7 irreversible filter if (tileComp->transform == 0) { + cover(84); // step 1 (even) for (i = 1; i <= end + 2; i += 2) { buf[i] = (int)(idwtKappa * buf[i]); @@ -2690,6 +2859,7 @@ void JPXStream::inverseTransform1D(JPXTileComp *tileComp, //----- 5-3 reversible filter } else { + cover(85); // step 1 (even) for (i = 3; i <= end; i += 2) { buf[i] -= (buf[i-1] + buf[i+1] + 2) >> 2; @@ -2718,6 +2888,7 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { //----- 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 || @@ -2728,6 +2899,7 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { // 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) { @@ -2744,6 +2916,7 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { // 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) { @@ -2765,6 +2938,7 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { // signed: clip if (tileComp->sgned) { + cover(89); minVal = -(1 << (tileComp->prec - 1)); maxVal = (1 << (tileComp->prec - 1)) - 1; dataPtr = tileComp->data; @@ -2772,11 +2946,14 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { 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; @@ -2785,6 +2962,7 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { // unsigned: inverse DC level shift and clip } else { + cover(90); maxVal = (1 << tileComp->prec) - 1; zeroVal = 1 << (tileComp->prec - 1); dataPtr = tileComp->data; @@ -2792,12 +2970,15 @@ GBool JPXStream::inverseMultiCompAndDC(JPXTile *tile) { 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; @@ -2930,10 +3111,10 @@ GBool JPXStream::readBits(int nBits, Guint *x) { int c; while (bitBufLen < nBits) { - if ((c = str->getChar()) == EOF) { + if (byteCount == 0 || (c = str->getChar()) == EOF) { return gFalse; } - ++byteCount; + --byteCount; if (bitBufSkip) { bitBuf = (bitBuf << 7) | (c & 0x7f); bitBufLen += 7; @@ -2948,8 +3129,16 @@ GBool JPXStream::readBits(int nBits, Guint *x) { return gTrue; } -void JPXStream::clearBitBuf() { +void JPXStream::startBitBuf(Guint byteCountA) { bitBufLen = 0; bitBufSkip = gFalse; - byteCount = 0; + byteCount = byteCountA; +} + +Guint JPXStream::finishBitBuf() { + if (bitBufSkip) { + str->getChar(); + --byteCount; + } + return byteCount; } diff --git a/Build/source/libs/xpdf/xpdf/JPXStream.h b/Build/source/libs/xpdf/xpdf/JPXStream.h index e64731db08a..e96e7d388e9 100644 --- a/Build/source/libs/xpdf/xpdf/JPXStream.h +++ b/Build/source/libs/xpdf/xpdf/JPXStream.h @@ -19,6 +19,7 @@ #include "Object.h" #include "Stream.h" +class JArithmeticDecoder; class JArithmeticDecoderStats; //------------------------------------------------------------------------ @@ -277,6 +278,7 @@ public: virtual ~JPXStream(); virtual StreamKind getKind() { return strJPX; } virtual void reset(); + virtual void close(); virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, char *indent); @@ -317,7 +319,8 @@ private: GBool readULong(Guint *x); GBool readNBytes(int nBytes, GBool signd, int *x); GBool readBits(int nBits, Guint *x); - void clearBitBuf(); + void startBitBuf(Guint byteCountA); + Guint finishBitBuf(); Guint nComps; // number of components Guint *bpc; // bits per component, for each component @@ -338,8 +341,7 @@ private: int bitBufLen; // number of bits in bitBuf GBool bitBufSkip; // true if next bit should be skipped // (for bit stuffing) - Guint byteCount; // number of bytes read since last call - // to clearBitBuf + Guint byteCount; // number of available bytes left Guint curX, curY, curComp; // current position for lookChar/getChar Guint readBuf; // read buffer diff --git a/Build/source/libs/xpdf/xpdf/Link.cc b/Build/source/libs/xpdf/xpdf/Link.cc index 898ca20c355..ae2de537e36 100644 --- a/Build/source/libs/xpdf/xpdf/Link.cc +++ b/Build/source/libs/xpdf/xpdf/Link.cc @@ -288,7 +288,7 @@ LinkDest::LinkDest(Array *a) { kind = destFitH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } top = obj2.getNum(); obj2.free(); @@ -302,7 +302,7 @@ LinkDest::LinkDest(Array *a) { kind = destFitV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } left = obj2.getNum(); obj2.free(); @@ -316,25 +316,25 @@ LinkDest::LinkDest(Array *a) { kind = destFitR; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } left = obj2.getNum(); obj2.free(); if (!a->get(3, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } bottom = obj2.getNum(); obj2.free(); if (!a->get(4, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } right = obj2.getNum(); obj2.free(); if (!a->get(5, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } top = obj2.getNum(); obj2.free(); @@ -356,7 +356,7 @@ LinkDest::LinkDest(Array *a) { kind = destFitBH; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } top = obj2.getNum(); obj2.free(); @@ -370,7 +370,7 @@ LinkDest::LinkDest(Array *a) { kind = destFitBV; if (!a->get(2, &obj2)->isNum()) { error(-1, "Bad annotation destination position"); - goto err1; + kind = destFit; } left = obj2.getNum(); obj2.free(); @@ -635,42 +635,13 @@ LinkUnknown::~LinkUnknown() { } //------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -LinkBorderStyle::LinkBorderStyle(LinkBorderType 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; -} - -LinkBorderStyle::~LinkBorderStyle() { - if (dash) { - gfree(dash); - } -} - -//------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ Link::Link(Dict *dict, GString *baseURI) { - Object obj1, obj2, obj3; - LinkBorderType borderType; - double borderWidth; - double *borderDash; - int borderDashLength; - double borderR, borderG, borderB; + Object obj1, obj2; double t; - int i; - borderStyle = NULL; action = NULL; ok = gFalse; @@ -715,97 +686,6 @@ Link::Link(Dict *dict, GString *baseURI) { y2 = t; } - // get the border style info - borderType = linkBorderSolid; - 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 = linkBorderSolid; - } else if (obj2.isName("D")) { - borderType = linkBorderDashed; - } else if (obj2.isName("B")) { - borderType = linkBorderEmbossed; - } else if (obj2.isName("I")) { - borderType = linkBorderEngraved; - } else if (obj2.isName("U")) { - borderType = linkBorderUnderlined; - } - } - 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 = linkBorderDashed; - 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 LinkBorderStyle(borderType, borderWidth, - borderDash, borderDashLength, - borderR, borderG, borderB); - // look for destination if (!dict->lookup("Dest", &obj1)->isNull()) { action = LinkAction::parseDest(&obj1); @@ -833,9 +713,6 @@ Link::Link(Dict *dict, GString *baseURI) { } Link::~Link() { - if (borderStyle) { - delete borderStyle; - } if (action) { delete action; } diff --git a/Build/source/libs/xpdf/xpdf/Link.h b/Build/source/libs/xpdf/xpdf/Link.h index 9f044204966..698f2c85294 100644 --- a/Build/source/libs/xpdf/xpdf/Link.h +++ b/Build/source/libs/xpdf/xpdf/Link.h @@ -302,42 +302,6 @@ private: }; //------------------------------------------------------------------------ -// LinkBorderStyle -//------------------------------------------------------------------------ - -enum LinkBorderType { - linkBorderSolid, - linkBorderDashed, - linkBorderEmbossed, - linkBorderEngraved, - linkBorderUnderlined -}; - -class LinkBorderStyle { -public: - - LinkBorderStyle(LinkBorderType typeA, double widthA, - double *dashA, int dashLengthA, - double rA, double gA, double bA); - ~LinkBorderStyle(); - - LinkBorderType 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: - - LinkBorderType type; - double width; - double *dash; - int dashLength; - double r, g, b; -}; - -//------------------------------------------------------------------------ // Link //------------------------------------------------------------------------ @@ -364,14 +328,10 @@ public: void getRect(double *xa1, double *ya1, double *xa2, double *ya2) { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; } - // Get the border style info. - LinkBorderStyle *getBorderStyle() { return borderStyle; } - private: double x1, y1; // lower left corner double x2, y2; // upper right corner - LinkBorderStyle *borderStyle; // border style LinkAction *action; // action GBool ok; // is link valid? }; diff --git a/Build/source/libs/xpdf/xpdf/OutputDev.cc b/Build/source/libs/xpdf/xpdf/OutputDev.cc index cfa41619e04..8d4763b7d83 100644 --- a/Build/source/libs/xpdf/xpdf/OutputDev.cc +++ b/Build/source/libs/xpdf/xpdf/OutputDev.cc @@ -55,6 +55,7 @@ void OutputDev::updateAll(GfxState *state) { updateLineCap(state); updateMiterLimit(state); updateLineWidth(state); + updateStrokeAdjust(state); updateFillColorSpace(state); updateFillColor(state); updateStrokeColorSpace(state); @@ -64,6 +65,7 @@ void OutputDev::updateAll(GfxState *state) { updateStrokeOpacity(state); updateFillOverprint(state); updateStrokeOverprint(state); + updateTransfer(state); updateFont(state); } diff --git a/Build/source/libs/xpdf/xpdf/OutputDev.h b/Build/source/libs/xpdf/xpdf/OutputDev.h index fdb0edcbe18..27dc0dd9c16 100644 --- a/Build/source/libs/xpdf/xpdf/OutputDev.h +++ b/Build/source/libs/xpdf/xpdf/OutputDev.h @@ -20,14 +20,18 @@ class GString; 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 @@ -61,6 +65,10 @@ public: // 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; @@ -73,6 +81,18 @@ public: // 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, Catalog *catalog, + GBool (*abortCheckCbk)(void *data) = NULL, + void *abortCheckCbkData = NULL) + { return gTrue; } + // Start a page. virtual void startPage(int pageNum, GfxState *state) {} @@ -91,9 +111,6 @@ public: double *getDefCTM() { return defCTM; } double *getDefICTM() { return defICTM; } - //----- link borders - virtual void drawLink(Link *link, Catalog *catalog) {} - //----- save/restore graphics state virtual void saveState(GfxState *state) {} virtual void restoreState(GfxState *state) {} @@ -108,6 +125,7 @@ public: 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) {} @@ -117,6 +135,7 @@ public: virtual void updateStrokeOpacity(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) {} @@ -138,14 +157,18 @@ public: double *mat, double *bbox, int x0, int y0, int x1, int y1, double xStep, double yStep) {} - virtual void functionShadedFill(GfxState *state, - GfxFunctionShading *shading) {} - virtual void axialShadedFill(GfxState *state, GfxAxialShading *shading) {} - virtual void radialShadedFill(GfxState *state, GfxRadialShading *shading) {} + 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) {} @@ -193,9 +216,31 @@ public: 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, Catalog *catalog) {} + +#if 1 //~tmp: turn off anti-aliasing temporarily + virtual GBool getVectorAntialias() { return gFalse; } + virtual void setVectorAntialias(GBool vaa) {} +#endif + private: double defCTM[6]; // default coordinate transform matrix diff --git a/Build/source/libs/xpdf/xpdf/PDFDoc.cc b/Build/source/libs/xpdf/xpdf/PDFDoc.cc index 92863e49e0e..c559eefcfb7 100644 --- a/Build/source/libs/xpdf/xpdf/PDFDoc.cc +++ b/Build/source/libs/xpdf/xpdf/PDFDoc.cc @@ -61,7 +61,6 @@ PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword, str = NULL; xref = NULL; catalog = NULL; - links = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif @@ -119,7 +118,6 @@ PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword, str = NULL; xref = NULL; catalog = NULL; - links = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif @@ -164,12 +162,15 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword, ok = gFalse; errCode = errNone; guiData = guiDataA; - fileName = NULL; + if (strA->getFileName()) { + fileName = strA->getFileName()->copy(); + } else { + fileName = NULL; + } file = NULL; str = strA; xref = NULL; catalog = NULL; - links = NULL; #ifndef DISABLE_OUTLINE outline = NULL; #endif @@ -234,9 +235,6 @@ PDFDoc::~PDFDoc() { if (fileName) { delete fileName; } - if (links) { - delete links; - } } // Check for a PDF header on this stream. Skip past some garbage @@ -288,7 +286,8 @@ GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { secHdlr->getOwnerPasswordOk(), secHdlr->getFileKey(), secHdlr->getFileKeyLength(), - secHdlr->getEncVersion()); + secHdlr->getEncVersion(), + secHdlr->getEncAlgorithm()); ret = gTrue; } else { // authorization failed @@ -307,73 +306,51 @@ GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) { return ret; } -void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool useMediaBox, GBool crop, - GBool doLinks, +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) { - Page *p; - if (globalParams->getPrintCommands()) { printf("***** page %d *****\n", page); } - p = catalog->getPage(page); - if (doLinks) { - if (links) { - delete links; - } - getLinks(p); - p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog, - abortCheckCbk, abortCheckCbkData); - } else { - p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog, - abortCheckCbk, abortCheckCbkData); - } + catalog->getPage(page)->display(out, hDPI, vDPI, + rotate, useMediaBox, crop, printing, catalog, + abortCheckCbk, abortCheckCbkData); } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, + 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, doLinks, + displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData); } } void PDFDoc::displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool doLinks, + GBool useMediaBox, GBool crop, GBool printing, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { - Page *p; - - p = catalog->getPage(page); - if (doLinks) { - if (links) { - delete links; - } - getLinks(p); - p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - links, catalog, abortCheckCbk, abortCheckCbkData); - } else { - p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - NULL, catalog, abortCheckCbk, abortCheckCbkData); - } + catalog->getPage(page)->displaySlice(out, hDPI, vDPI, + rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, + abortCheckCbk, abortCheckCbkData); } -Links *PDFDoc::takeLinks() { - Links *ret; +Links *PDFDoc::getLinks(int page) { + return catalog->getPage(page)->getLinks(catalog); +} - ret = links; - links = NULL; - return ret; +void PDFDoc::processLinks(OutputDev *out, int page) { + catalog->getPage(page)->processLinks(out, catalog); } GBool PDFDoc::isLinearized() { @@ -385,7 +362,8 @@ GBool PDFDoc::isLinearized() { obj1.initNull(); parser = new Parser(xref, new Lexer(xref, - str->makeSubStream(str->getStart(), gFalse, 0, &obj1))); + str->makeSubStream(str->getStart(), gFalse, 0, &obj1)), + gTrue); parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); @@ -422,10 +400,3 @@ GBool PDFDoc::saveAs(GString *name) { fclose(f); return gTrue; } - -void PDFDoc::getLinks(Page *page) { - Object obj; - - links = new Links(page->getAnnots(&obj), catalog->getBaseURI()); - obj.free(); -} diff --git a/Build/source/libs/xpdf/xpdf/PDFDoc.h b/Build/source/libs/xpdf/xpdf/PDFDoc.h index a1f42c08d94..208b61efa97 100644 --- a/Build/source/libs/xpdf/xpdf/PDFDoc.h +++ b/Build/source/libs/xpdf/xpdf/PDFDoc.h @@ -86,23 +86,23 @@ public: 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 doLinks, + 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 doLinks, + 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 doLinks, + GBool useMediaBox, GBool crop, GBool printing, int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); @@ -113,13 +113,16 @@ public: // Returns the links for the current page, transferring ownership to // the caller. - Links *takeLinks(); + Links *getLinks(int page); // Find a named destination. Returns the link destination, or // NULL if <name> 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; } @@ -160,7 +163,6 @@ private: GBool setup(GString *ownerPassword, GString *userPassword); void checkHeader(); GBool checkEncryption(GString *ownerPassword, GString *userPassword); - void getLinks(Page *page); GString *fileName; FILE *file; @@ -169,7 +171,6 @@ private: double pdfVersion; XRef *xref; Catalog *catalog; - Links *links; #ifndef DISABLE_OUTLINE Outline *outline; #endif diff --git a/Build/source/libs/xpdf/xpdf/PSTokenizer.cc b/Build/source/libs/xpdf/xpdf/PSTokenizer.cc index a65c3241c0f..0ad37618563 100644 --- a/Build/source/libs/xpdf/xpdf/PSTokenizer.cc +++ b/Build/source/libs/xpdf/xpdf/PSTokenizer.cc @@ -95,7 +95,7 @@ GBool PSTokenizer::getToken(char *buf, int size, int *length) { } else if (c == '<') { while ((c = lookChar()) != EOF) { getChar(); - if (i < size - 1) { + if (i < size - 1 && specialChars[c] != 1) { buf[i++] = c; } if (c == '>') { diff --git a/Build/source/libs/xpdf/xpdf/Page.cc b/Build/source/libs/xpdf/xpdf/Page.cc index 47171571cff..2a7540b06c0 100644 --- a/Build/source/libs/xpdf/xpdf/Page.cc +++ b/Build/source/libs/xpdf/xpdf/Page.cc @@ -2,7 +2,7 @@ // // Page.cc // -// Copyright 1996-2003 Glyph & Cog, LLC +// Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== @@ -26,9 +26,37 @@ #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 //------------------------------------------------------------------------ @@ -74,6 +102,12 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) { artBox = cropBox; readBox(dict, "ArtBox", &artBox); + // clip all other boxes to the media box + cropBox.clipTo(&mediaBox); + bleedBox.clipTo(&mediaBox); + trimBox.clipTo(&mediaBox); + artBox.clipTo(&mediaBox); + // rotate dict->lookup("Rotate", &obj1); if (obj1.isInt()) { @@ -213,32 +247,47 @@ Page::~Page() { contents.free(); } +Links *Page::getLinks(Catalog *catalog) { + Links *links; + Object obj; + + links = new Links(getAnnots(&obj), catalog->getBaseURI()); + obj.free(); + return links; +} + void Page::display(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, - Links *links, Catalog *catalog, + GBool printing, Catalog *catalog, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, - -1, -1, -1, -1, links, catalog, + -1, -1, -1, -1, printing, catalog, 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, - Links *links, Catalog *catalog, + GBool printing, Catalog *catalog, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData) { #ifndef PDF_PARSER_ONLY - PDFRectangle *mediaBox, *cropBox, *baseBox; + PDFRectangle *mediaBox, *cropBox; PDFRectangle box; Gfx *gfx; Object obj; - Link *link; Annots *annotList; - double kx, ky; + Dict *acroForm; int i; + if (!out->checkPageSlice(this, hDPI, vDPI, rotate, useMediaBox, crop, + sliceX, sliceY, sliceW, sliceH, + printing, catalog, + abortCheckCbk, abortCheckCbkData)) { + return; + } + rotate += getRotate(); if (rotate >= 360) { rotate -= 360; @@ -246,61 +295,12 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, rotate += 360; } - mediaBox = getMediaBox(); + makeBox(hDPI, vDPI, rotate, useMediaBox, out->upsideDown(), + sliceX, sliceY, sliceW, sliceH, &box, &crop); cropBox = getCropBox(); - if (sliceW >= 0 && sliceH >= 0) { - baseBox = useMediaBox ? mediaBox : cropBox; - kx = 72.0 / hDPI; - ky = 72.0 / vDPI; - if (rotate == 90) { - if (out->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 (out->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 (out->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 (out->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; - } 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", @@ -319,26 +319,25 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, } obj.free(); - // draw links - if (links) { - gfx->saveState(); - for (i = 0; i < links->getNumLinks(); ++i) { - link = links->getLink(i); - out->drawLink(link, catalog); + // draw annotations + annotList = new Annots(xref, catalog, getAnnots(&obj)); + obj.free(); + acroForm = catalog->getAcroForm()->isDict() ? + catalog->getAcroForm()->getDict() : NULL; + if (acroForm) { + if (acroForm->lookup("NeedAppearances", &obj)) { + if (obj.isBool() && obj.getBool()) { + annotList->generateAppearances(acroForm); + } } - gfx->restoreState(); - out->dump(); + obj.free(); } - - // draw non-link annotations - annotList = new Annots(xref, catalog, annots.fetch(xref, &obj)); - obj.free(); if (annotList->getNumAnnots() > 0) { if (globalParams->getPrintCommands()) { printf("***** Annotations\n"); } for (i = 0; i < annotList->getNumAnnots(); ++i) { - annotList->getAnnot(i)->draw(gfx); + annotList->getAnnot(i)->draw(gfx, printing); } out->dump(); } @@ -348,9 +347,82 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, #endif } -void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, - int rotate, GBool upsideDown) { +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, Catalog *catalog) { + Links *links; + int i; + + links = getLinks(catalog); + for (i = 0; i < links->getNumLinks(); ++i) { + out->processLink(links->getLink(i), catalog); + } + delete links; +} + #ifndef PDF_PARSER_ONLY +void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, + int rotate, GBool useMediaBox, GBool upsideDown) { GfxState *state; int i; @@ -360,10 +432,12 @@ void Page::getDefaultCTM(double *ctm, double hDPI, double vDPI, } else if (rotate < 0) { rotate += 360; } - state = new GfxState(hDPI, vDPI, getMediaBox(), rotate, upsideDown); + state = new GfxState(hDPI, vDPI, + useMediaBox ? getMediaBox() : getCropBox(), + rotate, upsideDown); for (i = 0; i < 6; ++i) { ctm[i] = state->getCTM()[i]; } delete state; -#endif } +#endif diff --git a/Build/source/libs/xpdf/xpdf/Page.h b/Build/source/libs/xpdf/xpdf/Page.h index 36f96e1ad60..cacc0d164bf 100644 --- a/Build/source/libs/xpdf/xpdf/Page.h +++ b/Build/source/libs/xpdf/xpdf/Page.h @@ -33,6 +33,7 @@ public: 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); }; //------------------------------------------------------------------------ @@ -112,6 +113,7 @@ public: 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(); } @@ -140,13 +142,16 @@ public: // Get annotations array. Object *getAnnots(Object *obj) { return annots.fetch(xref, obj); } + // Return a list of links. + Links *getLinks(Catalog *catalog); + // 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, - Links *links, Catalog *catalog, + GBool printing, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL); @@ -154,13 +159,22 @@ public: void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, - Links *links, Catalog *catalog, + GBool printing, Catalog *catalog, 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, Catalog *catalog); + +#ifndef PDF_PARSER_ONLY // Get the page's default CTM. void getDefaultCTM(double *ctm, double hDPI, double vDPI, - int rotate, GBool upsideDown); + int rotate, GBool useMediaBox, GBool upsideDown); +#endif private: diff --git a/Build/source/libs/xpdf/xpdf/Parser.cc b/Build/source/libs/xpdf/xpdf/Parser.cc index af7c933114a..c1fc715219f 100644 --- a/Build/source/libs/xpdf/xpdf/Parser.cc +++ b/Build/source/libs/xpdf/xpdf/Parser.cc @@ -16,15 +16,16 @@ #include "Object.h" #include "Array.h" #include "Dict.h" +#include "Decrypt.h" #include "Parser.h" #include "XRef.h" #include "Error.h" -#include "Decrypt.h" -Parser::Parser(XRef *xrefA, Lexer *lexerA) { +Parser::Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA) { xref = xrefA; lexer = lexerA; inlineImg = 0; + allowStreams = allowStreamsA; lexer->getObj(&buf1); lexer->getObj(&buf2); } @@ -35,17 +36,16 @@ Parser::~Parser() { delete lexer; } -Object *Parser::getObj(Object *obj, - Guchar *fileKey, int keyLength, +Object *Parser::getObj(Object *obj, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen) { char *key; Stream *str; Object obj2; int num; - Decrypt *decrypt; - GString *s; - char *p; - int i; + DecryptStream *decrypt; + GString *s, *s2; + int c; // refill buffer after inline image data if (inlineImg == 2) { @@ -61,7 +61,8 @@ Object *Parser::getObj(Object *obj, shift(); obj->initArray(xref); while (!buf1.isCmd("]") && !buf1.isEOF()) - obj->arrayAdd(getObj(&obj2, fileKey, keyLength, objNum, objGen)); + obj->arrayAdd(getObj(&obj2, fileKey, encAlgorithm, keyLength, + objNum, objGen)); if (buf1.isEOF()) error(getPos(), "End of file inside array"); shift(); @@ -81,18 +82,18 @@ Object *Parser::getObj(Object *obj, gfree(key); break; } - obj->dictAdd(key, getObj(&obj2, fileKey, keyLength, objNum, objGen)); + obj->dictAdd(key, getObj(&obj2, fileKey, encAlgorithm, keyLength, + objNum, objGen)); } } if (buf1.isEOF()) error(getPos(), "End of file inside dictionary"); - if (buf2.isCmd("stream")) { - if ((str = makeStream(obj))) { + // 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))) { obj->initStream(str); - if (fileKey) { - str->getBaseStream()->doDecryption(fileKey, keyLength, - objNum, objGen); - } } else { obj->free(); obj->initError(); @@ -115,15 +116,19 @@ Object *Parser::getObj(Object *obj, // string } else if (buf1.isString() && fileKey) { - buf1.copy(obj); - s = obj->getString(); - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); - for (i = 0, p = obj->getString()->getCString(); - i < s->getLength(); - ++i, ++p) { - *p = decrypt->decryptByte(*p); + 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 @@ -135,7 +140,9 @@ Object *Parser::getObj(Object *obj, return obj; } -Stream *Parser::makeStream(Object *dict) { +Stream *Parser::makeStream(Object *dict, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, + int objNum, int objGen) { Object obj; BaseStream *baseStr; Stream *str; @@ -186,6 +193,12 @@ Stream *Parser::makeStream(Object *dict) { // 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); diff --git a/Build/source/libs/xpdf/xpdf/Parser.h b/Build/source/libs/xpdf/xpdf/Parser.h index b583baf6398..a109558b026 100644 --- a/Build/source/libs/xpdf/xpdf/Parser.h +++ b/Build/source/libs/xpdf/xpdf/Parser.h @@ -25,14 +25,14 @@ class Parser { public: // Constructor. - Parser(XRef *xrefA, Lexer *lexerA); + Parser(XRef *xrefA, Lexer *lexerA, GBool allowStreamsA); // Destructor. ~Parser(); // Get the next object from the input stream. - Object *getObj(Object *obj, - Guchar *fileKey = NULL, int keyLength = 0, + Object *getObj(Object *obj, Guchar *fileKey = NULL, + CryptAlgorithm encAlgorithm = cryptRC4, int keyLength = 0, int objNum = 0, int objGen = 0); // Get stream. @@ -45,10 +45,13 @@ 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); + Stream *makeStream(Object *dict, Guchar *fileKey, + CryptAlgorithm encAlgorithm, int keyLength, + int objNum, int objGen); void shift(); }; diff --git a/Build/source/libs/xpdf/xpdf/SecurityHandler.cc b/Build/source/libs/xpdf/xpdf/SecurityHandler.cc index 40e9f59fb15..ea0f9341dd3 100644 --- a/Build/source/libs/xpdf/xpdf/SecurityHandler.cc +++ b/Build/source/libs/xpdf/xpdf/SecurityHandler.cc @@ -153,6 +153,7 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, permObj.isInt()) { encVersion = versionObj.getInt(); encRevision = revisionObj.getInt(); + encAlgorithm = cryptRC4; // revision 2 forces a 40-bit key - some buggy PDF generators // set the Length value incorrectly if (encRevision == 2 || !lengthObj.isInt()) { @@ -172,7 +173,8 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, !strcmp(streamFilterObj.getName(), stringFilterObj.getName())) { if (cryptFiltersObj.dictLookup(streamFilterObj.getName(), &cryptFilterObj)->isDict()) { - if (cryptFilterObj.dictLookup("CFM", &cfmObj)->isName("V2")) { + cryptFilterObj.dictLookup("CFM", &cfmObj); + if (cfmObj.isName("V2")) { encVersion = 2; encRevision = 3; if (cryptFilterObj.dictLookup("Length", &cfLengthObj)->isInt()) { @@ -180,6 +182,15 @@ StandardSecurityHandler::StandardSecurityHandler(PDFDoc *docA, 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(); } cfmObj.free(); } @@ -312,6 +323,7 @@ ExternalSecurityHandler::ExternalSecurityHandler(PDFDoc *docA, { encryptDictA->copy(&encryptDict); xsh = xshA; + encAlgorithm = cryptRC4; //~ this should be obtained via getKey ok = gFalse; if (!(*xsh->newDoc)(xsh->handlerData, (XpdfDoc)docA, diff --git a/Build/source/libs/xpdf/xpdf/SecurityHandler.h b/Build/source/libs/xpdf/xpdf/SecurityHandler.h index 127acb7695e..a27868c249d 100644 --- a/Build/source/libs/xpdf/xpdf/SecurityHandler.h +++ b/Build/source/libs/xpdf/xpdf/SecurityHandler.h @@ -74,6 +74,7 @@ public: virtual Guchar *getFileKey() = 0; virtual int getFileKeyLength() = 0; virtual int getEncVersion() = 0; + virtual CryptAlgorithm getEncAlgorithm() = 0; protected: @@ -100,6 +101,7 @@ public: virtual Guchar *getFileKey() { return fileKey; } virtual int getFileKeyLength() { return fileKeyLength; } virtual int getEncVersion() { return encVersion; } + virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } private: @@ -109,6 +111,7 @@ private: int fileKeyLength; int encVersion; int encRevision; + CryptAlgorithm encAlgorithm; GBool encryptMetadata; GString *ownerKey, *userKey; @@ -138,6 +141,7 @@ public: virtual Guchar *getFileKey() { return fileKey; } virtual int getFileKeyLength() { return fileKeyLength; } virtual int getEncVersion() { return encVersion; } + virtual CryptAlgorithm getEncAlgorithm() { return encAlgorithm; } private: @@ -148,6 +152,7 @@ private: Guchar fileKey[16]; int fileKeyLength; int encVersion; + CryptAlgorithm encAlgorithm; GBool ok; }; #endif // ENABLE_PLUGINS diff --git a/Build/source/libs/xpdf/xpdf/Stream.cc b/Build/source/libs/xpdf/xpdf/Stream.cc index 5fa7791c436..68abafa7b8d 100644 --- a/Build/source/libs/xpdf/xpdf/Stream.cc +++ b/Build/source/libs/xpdf/xpdf/Stream.cc @@ -27,7 +27,6 @@ #include "Error.h" #include "Object.h" #include "Lexer.h" -#include "Decrypt.h" #include "GfxState.h" #include "Stream.h" #include "JBIG2Stream.h" @@ -142,6 +141,7 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { int encoding; GBool endOfLine, byteAlign, endOfBlock, black; int columns, rows; + int colorXform; Object globals, obj; if (!strcmp(name, "ASCIIHexDecode") || !strcmp(name, "AHx")) { @@ -227,7 +227,14 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { str = new CCITTFaxStream(str, encoding, endOfLine, byteAlign, columns, rows, endOfBlock, black); } else if (!strcmp(name, "DCTDecode") || !strcmp(name, "DCT")) { - str = new DCTStream(str); + 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; @@ -273,18 +280,10 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { BaseStream::BaseStream(Object *dictA) { dict = *dictA; - decrypt = NULL; } BaseStream::~BaseStream() { dict.free(); - if (decrypt) - delete decrypt; -} - -void BaseStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - decrypt = new Decrypt(fileKey, keyLength, objNum, objGen); } //------------------------------------------------------------------------ @@ -402,8 +401,6 @@ void ImageStream::skipLine() { StreamPredictor::StreamPredictor(Stream *strA, int predictorA, int widthA, int nCompsA, int nBitsA) { - int totalBits; - str = strA; predictor = predictorA; width = widthA; @@ -413,7 +410,6 @@ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, ok = gFalse; nVals = width * nComps; - totalBits = nVals * nBits; if (width <= 0 || nComps <= 0 || nBits <= 0 || nComps >= INT_MAX / nBits || width >= INT_MAX / nComps / nBits || @@ -421,8 +417,8 @@ StreamPredictor::StreamPredictor(Stream *strA, int predictorA, return; } pixBytes = (nComps * nBits + 7) >> 3; - rowBytes = ((totalBits + 7) >> 3) + pixBytes; - if (rowBytes < 0) { + rowBytes = ((nVals * nBits + 7) >> 3) + pixBytes; + if (rowBytes <= 0) { return; } predLine = (Guchar *)gmalloc(rowBytes); @@ -550,8 +546,8 @@ GBool StreamPredictor::getNextLine() { inBuf = (inBuf << 8) | (predLine[j++] & 0xff); inBits += 8; } - upLeftBuf[kk] = (upLeftBuf[kk] + - (inBuf >> (inBits - nBits))) & bitMask; + upLeftBuf[kk] = (Guchar)((upLeftBuf[kk] + + (inBuf >> (inBits - nBits))) & bitMask); inBits -= nBits; outBuf = (outBuf << nBits) | upLeftBuf[kk]; outBits += nBits; @@ -614,8 +610,6 @@ void FileStream::reset() { saved = gTrue; bufPtr = bufEnd = buf; bufPos = start; - if (decrypt) - decrypt->reset(); } void FileStream::close() { @@ -633,7 +627,6 @@ void FileStream::close() { GBool FileStream::fillBuf() { int n; - char *p; bufPos += bufEnd - buf; bufPtr = bufEnd = buf; @@ -650,11 +643,6 @@ GBool FileStream::fillBuf() { if (bufPtr >= bufEnd) { return gFalse; } - if (decrypt) { - for (p = buf; p < bufEnd; ++p) { - *p = (char)decrypt->decryptByte((Guchar)*p); - } - } return gTrue; } @@ -743,9 +731,6 @@ Stream *MemStream::makeSubStream(Guint startA, GBool limited, void MemStream::reset() { bufPtr = buf + start; - if (decrypt) { - decrypt->reset(); - } } void MemStream::close() { @@ -773,25 +758,6 @@ void MemStream::moveStart(int delta) { bufPtr = buf + start; } -void MemStream::doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen) { - char *newBuf; - char *p, *q; - - this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen); - if (decrypt) { - newBuf = (char *)gmalloc(length); - for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) { - *q = (char)decrypt->decryptByte((Guchar)*p); - } - bufEnd = newBuf + length; - bufPtr = newBuf + (bufPtr - (buf + start)); - start = 0; - buf = newBuf; - needFree = gTrue; - } -} - //------------------------------------------------------------------------ // EmbedStream //------------------------------------------------------------------------ @@ -1286,8 +1252,8 @@ CCITTFaxStream::CCITTFaxStream(Stream *strA, int encodingA, GBool endOfLineA, rows = rowsA; endOfBlock = endOfBlockA; black = blackA; - refLine = (short *)gmallocn(columns + 4, sizeof(short)); - codingLine = (short *)gmallocn(columns + 3, sizeof(short)); + refLine = (short *)gmallocn(columns + 3, sizeof(short)); + codingLine = (short *)gmallocn(columns + 2, sizeof(short)); eof = gFalse; row = 0; @@ -1315,7 +1281,7 @@ void CCITTFaxStream::reset() { nextLine2D = encoding < 0; inputBits = 0; codingLine[0] = 0; - codingLine[1] = refLine[2] = columns; + codingLine[1] = columns; a0 = 1; buf = EOF; @@ -1351,8 +1317,27 @@ int CCITTFaxStream::lookChar() { // 2-D encoding if (nextLine2D) { - for (i = 0; codingLine[i] < columns; ++i) + // state: + // a0New = current position in coding line (0 <= a0New <= columns) + // codingLine[a0] = last change in coding line + // (black-to-white if a0 is even, + // white-to-black if a0 is odd) + // refLine[b1] = next change in reference line of opposite color + // to a0 + // invariants: + // 0 <= codingLine[a0] <= a0New + // <= refLine[b1] <= refLine[b1+1] <= columns + // 0 <= a0 <= columns+1 + // refLine[0] = 0 + // refLine[n] = refLine[n+1] = columns + // -- for some 1 <= n <= columns+1 + // end condition: + // 0 = codingLine[0] <= codingLine[1] < codingLine[2] < ... + // < codingLine[n-1] < codingLine[n] = columns + // -- where 1 <= n <= columns+1 + for (i = 0; codingLine[i] < columns; ++i) { refLine[i] = codingLine[i]; + } refLine[i] = refLine[i + 1] = columns; b1 = 1; a0New = codingLine[a0 = 0] = 0; @@ -1384,68 +1369,93 @@ int CCITTFaxStream::lookChar() { } while (code3 >= 64); } if (code1 > 0 || code2 > 0) { - codingLine[a0 + 1] = a0New + code1; + if (a0New + code1 <= columns) { + codingLine[a0 + 1] = a0New + code1; + } else { + codingLine[a0 + 1] = columns; + } ++a0; - a0New = codingLine[a0 + 1] = codingLine[a0] + code2; + if (codingLine[a0] + code2 <= columns) { + codingLine[a0 + 1] = codingLine[a0] + code2; + } else { + codingLine[a0 + 1] = columns; + } ++a0; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + a0New = codingLine[a0]; + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } } break; case twoDimVert0: - a0New = codingLine[++a0] = refLine[b1]; if (refLine[b1] < columns) { + a0New = codingLine[++a0] = refLine[b1]; ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } + } else { + a0New = codingLine[++a0] = columns; } break; case twoDimVertR1: - a0New = codingLine[++a0] = refLine[b1] + 1; - if (refLine[b1] < columns) { + if (refLine[b1] + 1 < columns) { + a0New = codingLine[++a0] = refLine[b1] + 1; ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } + } else { + a0New = codingLine[++a0] = columns; } break; case twoDimVertL1: - if (a0 == 0 || refLine[b1] - 1 > a0New) { + if (refLine[b1] - 1 > a0New || (a0 == 0 && refLine[b1] == 1)) { a0New = codingLine[++a0] = refLine[b1] - 1; --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } } break; case twoDimVertR2: - a0New = codingLine[++a0] = refLine[b1] + 2; - if (refLine[b1] < columns) { + if (refLine[b1] + 2 < columns) { + a0New = codingLine[++a0] = refLine[b1] + 2; ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } + } else { + a0New = codingLine[++a0] = columns; } break; case twoDimVertL2: - if (a0 == 0 || refLine[b1] - 2 > a0New) { + if (refLine[b1] - 2 > a0New || (a0 == 0 && refLine[b1] == 2)) { a0New = codingLine[++a0] = refLine[b1] - 2; --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } } break; case twoDimVertR3: - a0New = codingLine[++a0] = refLine[b1] + 3; - if (refLine[b1] < columns) { + if (refLine[b1] + 3 < columns) { + a0New = codingLine[++a0] = refLine[b1] + 3; ++b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } + } else { + a0New = codingLine[++a0] = columns; } break; case twoDimVertL3: - if (a0 == 0 || refLine[b1] - 3 > a0New) { + if (refLine[b1] - 3 > a0New || (a0 == 0 && refLine[b1] == 3)) { a0New = codingLine[++a0] = refLine[b1] - 3; --b1; - while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns) + while (refLine[b1] <= a0New && refLine[b1] < columns) { b1 += 2; + } } break; case EOF: @@ -1469,16 +1479,18 @@ int CCITTFaxStream::lookChar() { } while (code3 >= 64); codingLine[a0+1] = codingLine[a0] + code1; ++a0; - if (codingLine[a0] >= columns) + if (codingLine[a0] >= columns) { break; + } code2 = 0; do { code2 += code3 = getBlackCode(); } while (code3 >= 64); codingLine[a0+1] = codingLine[a0] + code2; ++a0; - if (codingLine[a0] >= columns) + if (codingLine[a0] >= columns) { break; + } } } @@ -1859,10 +1871,11 @@ static int dctZigZag[64] = { 63 }; -DCTStream::DCTStream(Stream *strA): +DCTStream::DCTStream(Stream *strA, GBool colorXformA): FilterStream(strA) { int i, j; + colorXform = colorXformA; progressive = interleaved = gFalse; width = height = 0; mcuWidth = mcuHeight = 0; @@ -1888,20 +1901,8 @@ DCTStream::DCTStream(Stream *strA): } DCTStream::~DCTStream() { - int i, j; - + close(); delete str; - if (progressive || !interleaved) { - for (i = 0; i < numComps; ++i) { - gfree(frameBuf[i]); - } - } else { - for (i = 0; i < numComps; ++i) { - for (j = 0; j < mcuHeight; ++j) { - gfree(rowBuf[i][j]); - } - } - } } void DCTStream::reset() { @@ -1915,7 +1916,6 @@ void DCTStream::reset() { numQuantTables = 0; numDCHuffTables = 0; numACHuffTables = 0; - colorXform = 0; gotJFIFMarker = gFalse; gotAdobeMarker = gFalse; restartInterval = 0; @@ -1943,14 +1943,18 @@ void DCTStream::reset() { mcuHeight *= 8; // figure out color transform - if (!gotAdobeMarker && numComps == 3) { - if (gotJFIFMarker) { - colorXform = 1; - } else if (compInfo[0].id == 82 && compInfo[1].id == 71 && - compInfo[2].id == 66) { // ASCII "RGB" - colorXform = 0; + 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 = 1; + colorXform = 0; } } @@ -2000,6 +2004,20 @@ void DCTStream::reset() { } } +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; @@ -2924,11 +2942,8 @@ GBool DCTStream::readBaselineSOF() { width = read16(); numComps = str->getChar(); if (numComps <= 0 || numComps > 4) { - error(getPos(), "Bad number of components in DCT stream", prec); - return gFalse; - } - if (numComps <= 0 || numComps > 4) { - error(getPos(), "Bad number of components in DCT stream", prec); + error(getPos(), "Bad number of components in DCT stream"); + numComps = 0; return gFalse; } if (prec != 8) { @@ -2962,11 +2977,6 @@ GBool DCTStream::readProgressiveSOF() { numComps = 0; return gFalse; } - if (numComps <= 0 || numComps > 4) { - error(getPos(), "Bad number of components in DCT stream"); - numComps = 0; - return gFalse; - } if (prec != 8) { error(getPos(), "Bad DCT precision %d", prec); return gFalse; @@ -3884,6 +3894,7 @@ FlateStream::FlateStream(Stream *strA, int predictor, int columns, } litCodeTab.codes = NULL; distCodeTab.codes = NULL; + memset(buf, 0, flateWindow); } FlateStream::~FlateStream() { @@ -4444,33 +4455,61 @@ void ASCII85Encoder::reset() { GBool ASCII85Encoder::fillBuf() { Gulong t; char buf1[5]; - int c; + int c0, c1, c2, c3; int n, i; - if (eof) + if (eof) { return gFalse; - t = 0; - for (n = 0; n < 4; ++n) { - if ((c = str->getChar()) == EOF) - break; - t = (t << 8) + c; } + c0 = str->getChar(); + c1 = str->getChar(); + c2 = str->getChar(); + c3 = str->getChar(); bufPtr = bufEnd = buf; - if (n > 0) { - if (n == 4 && t == 0) { + 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 { - if (n < 4) - t <<= 8 * (4 - n); for (i = 4; i >= 0; --i) { buf1[i] = (char)(t % 85 + 0x21); t /= 85; } - for (i = 0; i <= n; ++i) { + for (i = 0; i <= 4; ++i) { *bufEnd++ = buf1[i]; if (++lineLen == 65) { *bufEnd++ = '\n'; @@ -4479,12 +4518,7 @@ GBool ASCII85Encoder::fillBuf() { } } } - if (n < 4) { - *bufEnd++ = '~'; - *bufEnd++ = '>'; - eof = gTrue; - } - return bufPtr < bufEnd; + return gTrue; } //------------------------------------------------------------------------ diff --git a/Build/source/libs/xpdf/xpdf/Stream.h b/Build/source/libs/xpdf/xpdf/Stream.h index e1e7bae4282..85a84691bd9 100644 --- a/Build/source/libs/xpdf/xpdf/Stream.h +++ b/Build/source/libs/xpdf/xpdf/Stream.h @@ -19,7 +19,6 @@ #include "gtypes.h" #include "Object.h" -class Decrypt; class BaseStream; //------------------------------------------------------------------------ @@ -46,6 +45,15 @@ enum StreamColorSpaceMode { }; //------------------------------------------------------------------------ + +// This is in Stream.h instead of Decrypt.h to avoid really annoying +// include file dependency loops. +enum CryptAlgorithm { + cryptRC4, + cryptAES +}; + +//------------------------------------------------------------------------ // Stream (base class) //------------------------------------------------------------------------ @@ -101,6 +109,10 @@ public: // 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; @@ -111,6 +123,9 @@ public: 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 <dict>. // Returns the new stream. Stream *addFilters(Object *dict); @@ -138,20 +153,14 @@ public: 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; - // Set decryption for this stream. - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); - -protected: - - Decrypt *decrypt; - private: Object dict; @@ -172,7 +181,9 @@ public: 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: @@ -318,8 +329,6 @@ public: virtual void setPos(Guint pos, int dir = 0); virtual Guint getStart() { return start; } virtual void moveStart(int delta); - virtual void doDecryption(Guchar *fileKey, int keyLength, - int objNum, int objGen); private: @@ -530,7 +539,7 @@ private: short getWhiteCode(); short getBlackCode(); short lookBits(int n); - void eatBits(int n) { inputBits -= n; } + void eatBits(int n) { if ((inputBits -= n) < 0) inputBits = 0; } }; //------------------------------------------------------------------------ @@ -566,10 +575,11 @@ struct DCTHuffTable { class DCTStream: public FilterStream { public: - DCTStream(Stream *strA); + 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, char *indent); @@ -586,7 +596,9 @@ private: DCTCompInfo compInfo[4]; // info for each component DCTScanInfo scanInfo; // info for the current scan int numComps; // number of components in image - int colorXform; // need YCbCr-to-RGB transform? + 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 diff --git a/Build/source/libs/xpdf/xpdf/XRef.cc b/Build/source/libs/xpdf/xpdf/XRef.cc index c5a6aca8a6f..367f99b2fe2 100644 --- a/Build/source/libs/xpdf/xpdf/XRef.cc +++ b/Build/source/libs/xpdf/xpdf/XRef.cc @@ -90,7 +90,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { objStr.streamReset(); obj1.initNull(); str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); - parser = new Parser(xref, new Lexer(xref, str)); + parser = new Parser(xref, new Lexer(xref, str), gFalse); for (i = 0; i < nObjects; ++i) { parser->getObj(&obj1); parser->getObj(&obj2); @@ -131,7 +131,7 @@ ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { str = new EmbedStream(objStr.getStream(), &obj1, gTrue, offsets[i+1] - offsets[i]); } - parser = new Parser(xref, new Lexer(xref, str)); + parser = new Parser(xref, new Lexer(xref, str), gFalse); parser->getObj(&objs[i]); while (str->getChar() != EOF) ; delete parser; @@ -283,7 +283,8 @@ GBool XRef::readXRef(Guint *pos) { obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, - str->makeSubStream(start + *pos, gFalse, 0, &obj))); + str->makeSubStream(start + *pos, gFalse, 0, &obj)), + gTrue); parser->getObj(&obj); // parse an old-style xref table @@ -624,7 +625,7 @@ GBool XRef::constructXRef() { size = 0; entries = NULL; - error(0, "PDF file is damaged - attempting to reconstruct xref table..."); + error(-1, "PDF file is damaged - attempting to reconstruct xref table..."); gotRoot = gFalse; streamEndsLen = streamEndsSize = 0; @@ -636,12 +637,16 @@ GBool XRef::constructXRef() { } 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))); + str->makeSubStream(pos + 7, gFalse, 0, &obj)), + gFalse); parser->getObj(&newTrailerDict); if (newTrailerDict.isDict()) { newTrailerDict.dictLookupNF("Root", &obj); @@ -724,7 +729,8 @@ GBool XRef::constructXRef() { } void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, - Guchar *fileKeyA, int keyLengthA, int encVersionA) { + Guchar *fileKeyA, int keyLengthA, int encVersionA, + CryptAlgorithm encAlgorithmA) { int i; encrypted = gTrue; @@ -739,6 +745,7 @@ void XRef::setEncryption(int permFlagsA, GBool ownerPasswordOkA, fileKey[i] = fileKeyA[i]; } encVersion = encVersionA; + encAlgorithm = encAlgorithmA; } GBool XRef::okToPrint(GBool ignoreOwnerPW) { @@ -777,7 +784,8 @@ Object *XRef::fetch(int num, int gen, Object *obj) { obj1.initNull(); parser = new Parser(this, new Lexer(this, - str->makeSubStream(start + e->offset, gFalse, 0, &obj1))); + str->makeSubStream(start + e->offset, gFalse, 0, &obj1)), + gTrue); parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); @@ -790,8 +798,8 @@ Object *XRef::fetch(int num, int gen, Object *obj) { delete parser; goto err; } - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, - num, gen); + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, + encAlgorithm, keyLength, num, gen); obj1.free(); obj2.free(); obj3.free(); diff --git a/Build/source/libs/xpdf/xpdf/XRef.h b/Build/source/libs/xpdf/xpdf/XRef.h index 91cf28403e2..6eb32b92ae8 100644 --- a/Build/source/libs/xpdf/xpdf/XRef.h +++ b/Build/source/libs/xpdf/xpdf/XRef.h @@ -85,7 +85,8 @@ public: // Set the encryption parameters. void setEncryption(int permFlagsA, GBool ownerPasswordOkA, - Guchar *fileKeyA, int keyLengthA, int encVersionA); + Guchar *fileKeyA, int keyLengthA, int encVersionA, + CryptAlgorithm encAlgorithmA); // Is the file encrypted? GBool isEncrypted() { return encrypted; } @@ -147,7 +148,8 @@ private: GBool ownerPasswordOk; // true if owner password is correct Guchar fileKey[16]; // file decryption key int keyLength; // length of key, in bytes - int encVersion; // encryption algorithm + int encVersion; // encryption version + CryptAlgorithm encAlgorithm; // encryption algorithm Guint getStartXref(); GBool readXRef(Guint *pos); diff --git a/Build/source/libs/xpdf/xpdf/config.h b/Build/source/libs/xpdf/xpdf/config.h index 0bd5541c2b0..81d4dd071b5 100644 --- a/Build/source/libs/xpdf/xpdf/config.h +++ b/Build/source/libs/xpdf/xpdf/config.h @@ -2,7 +2,7 @@ // // config.h // -// Copyright 1996-2005 Glyph & Cog, LLC +// Copyright 1996-2007 Glyph & Cog, LLC // //======================================================================== @@ -14,26 +14,25 @@ //------------------------------------------------------------------------ // xpdf version -#define xpdfVersion "3.01" -#define xpdfVersionNum 3.01 +#define xpdfVersion "3.02" +#define xpdfVersionNum 3.02 #define xpdfMajorVersion 3 -#define xpdfMinorVersion 1 +#define xpdfMinorVersion 2 #define xpdfUpdateVersion 0 #define xpdfMajorVersionStr "3" -#define xpdfMinorVersionStr "1" +#define xpdfMinorVersionStr "2" #define xpdfUpdateVersionStr "0" // supported PDF version -// xpdf says only 1.5, but 1.7 is the same for pdfTeX's purpose #define supportedPDFVersionStr "1.7" #define supportedPDFVersionNum 1.7 // copyright notice -#define xpdfCopyright "Copyright 1996-2005 Glyph & Cog, LLC" +#define xpdfCopyright "Copyright 1996-2007 Glyph & Cog, LLC" // Windows resource file stuff -#define winxpdfVersion "WinXpdf 3.01" -#define xpdfCopyrightAmp "Copyright 1996-2005 Glyph && Cog, LLC" +#define winxpdfVersion "WinXpdf 3.02" +#define xpdfCopyrightAmp "Copyright 1996-2007 Glyph && Cog, LLC" //------------------------------------------------------------------------ // paper size |